РЕДАКТИРОВАТЬ: я немного изменить этот ответ. Я оставлю оригинальный ответ ниже.
В своем другом ответе я прокомментировал, что лучше всего будет найти встроенный модуль Python, который будет выполнять распаковку. Я не мог придумать ни одного, но, возможно, мне следовало искать в Google. @ Джон Мачин дал ответ, который показал, как это сделать: использовать модуль Python struct
. Поскольку это написано на C, оно должно быть быстрее, чем мое чистое решение на Python. (На самом деле я ничего не измерял, так что это предположение.)
Я согласен, что логика в исходном коде "непифонова". Возвращать дозорное значение не лучше; лучше либо вернуть действительное значение, либо вызвать исключение. Другой способ сделать это - вернуть список допустимых значений, а также другой список недопустимых значений. Поскольку @John Machin предлагал код для получения допустимых значений, я подумал, что напишу здесь версию, которая возвращает два списка.
ПРИМЕЧАНИЕ. Возможно, наилучшим из возможных ответов было бы взять ответ @John Machin и изменить его, чтобы сохранить недопустимые значения в файле для возможного последующего просмотра. Его ответ дает ответы по одному, поэтому нет необходимости составлять большой список проанализированных записей; и сохранение плохих строк на диск означает, что нет необходимости создавать возможно большой список плохих строк.
import struct
def parse_records(self):
"""
returns a tuple: (good, bad)
good is a list of valid records (as tuples)
bad is a list of tuples: (line_num, line, err)
"""
cols = self.Columns()
unpack_fmt = ""
sign_checks = []
start = 0
for colx, info in enumerate(cols, 1):
clen = info.columnLength
if clen < 1:
raise ValueError("Column %d: Bad columnLength %r" % (colx, clen))
if info.skipColumn:
unpack_fmt += str(clen) + "x"
else:
unpack_fmt += str(clen) + "s"
if info.hasSignage:
sign_checks.append(start)
start += clen
expected_len = start
unpack = struct.Struct(unpack_fmt).unpack
good = []
bad = []
for line_num, line in enumerate(self.whatever_the_list_of_lines_is, 1):
if len(line) != expected_len:
bad.append((line_num, line, "bad length"))
continue
if not all(line[i] in '+-' for i in sign_checks):
bad.append((line_num, line, "sign check failed"))
continue
good.append(unpack(line))
return good, bad
ОРИГИНАЛЬНЫЙ ТЕКСТ ОТВЕТА:
Этот ответ должен быть намного быстрее, если информация self.Columns()
одинакова для всех записей. Мы делаем обработку информации self.Columns()
один раз и создаем пару списков, которые содержат именно то, что нам нужно для обработки записи.
Этот код показывает, как вычислить parsedList
, но на самом деле не выдает его, не возвращает и не делает с ним ничего. Очевидно, вам нужно это изменить.
def parse_records(self):
cols = self.Columns()
slices = []
sign_checks = []
start = 0
for info in cols:
if info.columnLength < 1:
raise ValueError, "bad columnLength"
end = start + info.columnLength
if not info.skipColumn:
tup = (start, end)
slices.append(tup)
if info.hasSignage:
sign_checks.append(start)
expected_len = end # or use (end - 1) to not count a newline
try:
for line in self.whatever_the_list_of_lines_is:
if len(line) != expected_len:
raise ValueError, "wrong length"
if not all(line[i] in '+-' for i in sign_checks):
raise ValueError, "wrong input"
parsedLine = [line[s:e] for s, e in slices]
except ValueError:
parsedLine = False