Уведомления

Группа в Telegram: @pythonsu

#1 Окт. 11, 2009 13:00:39

knkd
От:
Зарегистрирован: 2009-06-14
Сообщения: 225
Репутация: +  0  -
Профиль   Отправить e-mail  

Форматное чтение из файла

sypper-pit
предлогает отрабатывать регулярными вырожениями, это вполне нормальный способ , и найти и отладить ошибку особо не представляется сложным
Ошибку в программе несложно. Но если входные данные сместятся - на выходе мы получим кашу. Так как регулярка будет одновременно обрабатывать всю строку, то локализовать ошибку будет сложно. Тем более то в случае ошибки регулярка сразу забракует всю строку или даже файл.
Когда считаем шагами - в случае запуска программы с отладочным ключём по печати результатов сразу видно место ошибки.

Griffon
Я вот так реализовал бы:
Блин. Мой старый вариант похуже будет.
До вот такого я не додумался :(
rep = {"s":str, "f":float, "i":int}



Офлайн

#2 Июль 16, 2010 17:45:56

knkd
От:
Зарегистрирован: 2009-06-14
Сообщения: 225
Репутация: +  0  -
Профиль   Отправить e-mail  

Форматное чтение из файла

Вот. Пришлось снова реализовать. Некоторые нелогичности обусловлены тем что сначала это было составной частью постороннего класса, а переделать лень :(
Никакого другого способа обработки скобочных выражений, кроме замены регекспами, мне сообразить неудалось :( :(

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import re

class FormatException(Exception):
pass

class Format(object):
"""
>>> string = ' 1 2 5 2.25 7 65.4'
>>> format = Format(r'2i3, 2(i3, f5)')
>>> print format.format_tuple
... (('i', 3), ('i', 3), ('i', 3), ('f', 5), ('i', 3), ('f', 5))
>>> print format(string)
... [1, 2, 5, 2.25, 7, 65.400000000000006]
"""

def __init__(self, format):
self._templ = {'f':float, 'i':int, 's':str}
self._patterns = self._compile_patterns()
self.format_tuple = self.parse_format(format)

def _compile_patterns(self):
patterns = {'find_brackets':re.compile(r'(\d{1,3})\s*(\([^\(\)]+\))'),
'dupl_brackets':re.compile(r'\((.+)\)'),
'txt_split' :re.compile(r'[^\w\d]+'),
'form_split' :re.compile(r'(\d{0,3})(\w\d{1,3})'),
'form_split_2' :re.compile(r'\s*(\w)(\d{1,3})\s*')}
return patterns

def parse_text(self, text):
res = []
for (num,string) in enumerate(text):
try:
res.append(self.parse_string(string))
except FormatException, E:
report = 'In row #{0}, pattern #{1} not detected.'\
''.format(num + 1, E.args[1])
raise FormatException(report, num + 1, E.args[1])
return tuple(res)

def parse_string(self, string):
format = self.format_tuple
cursor = 0
res = []
for (num,item) in enumerate(format):
try:
start = cursor
end = cursor + item[1]
slise = string[start:end]
slise = self._templ[item[0].lower()](slise)
cursor = end
res.append(slise)
except:
report = 'Pattern #{0} in format string not detect.'\
''.format(num + 1)
raise FormatException(report, num + 1)
return res

def __call__(self, data):
if isinstance(data, str):
return self.parse_string(data)
else:
return self.parse_text(data)

## Функція розбирає строку формату на кортеж із типом даних
## і кількістю символів.
def parse_format(self, fstring):
## Вкладена функція що заміняє дужки із цифрою перед ними на
## вміст дужок помножений на цифру.
def repl_brackets(match):
pattern = self._patterns['dupl_brackets']
(num,text) = match.groups()
text = pattern.sub(lambda t: t.groups()[0], text)
return (text+', ') * int(num)

pattern = self._patterns['find_brackets']
# Цикл повторюється доки не будуть видалені усі парні дужки.
# Якщо залишаться непарні дужки - буде сгенеровано виключення.
while True:
lbrack = fstring.find('(')
rbrack = fstring.find(')')
if (lbrack >=0 and rbrack >=0):
fstring = pattern.sub(repl_brackets, fstring)
elif (not lbrack >=0 and rbrack >=0) or \
(lbrack >=0 and not rbrack >=0):
raise FormatException('Brackets not paired!')
else:
break
pattern = self._patterns['txt_split']
fstring = tuple([x for x in pattern.split(fstring) if len(x)>0])

# Розгортаємо форматну строку у найбільш просту форму.
pattern = self._patterns['form_split']
format = [pattern.findall(x)[0] for x in fstring]
new = []
pattern = self._patterns['form_split_2']
for item in format:
# print item
if len(item[0])>0:
new_item = (int(item[0]), item[1])
else:
new_item = (1, item[1])
for i in xrange(new_item[0]):
new_item2 = pattern.split(new_item[1])
if len(new_item2)>0:
new_item2 = (new_item2[1], int(new_item2[2]))
new.append(new_item2)
return tuple(new)


if __name__ == '__main__':
string = ' 1 2 5 6.55 7 65.3'

text = [ ' 1 2 5 6.55 7 65.3',
' 1 2 5 6.55 7 55.3',
' 1 2 5 6.55 7 65.3', ]

format = Format(r'2i3, 2(i3, F5)')
print format.format_tuple
print format(string)
print format(text)



Отредактировано (Июль 16, 2010 17:47:46)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version