Python Iterator странно пропускает элементы - PullRequest
0 голосов
/ 24 сентября 2018

Как часть программы, которая декодирует коммуникационный протокол (EDIFACT MSCONS), у меня есть класс, который дает мне следующий «сегмент» сообщения.Сегменты ограничены апострофом «».Могут быть новые строки после «» или нет.Вот код для этого класса:

class SegmentGenerator:
def __init__(self, filename):
    try:
        fh = open(filename)
    except IOError:
        print ("Error: file " + filename + " not found!")
        sys.exit(2)
    lines=[]
    for line in fh:
        line = line.rstrip()
        lines.append(line)
    if len(lines) == 1:
        msg = lines[0]
    else:
        msg = ''
        for line in lines:
            msg = msg + line.rstrip()
    self.segments=msg.split("'")
    self.iterator=iter(self.segments)

def next(self):
    try:
        return next(self.iterator)
    except StopIteration:
        return None

if __name__ == '__main__': #testing only
    sg = SegmentGenerator('MSCONS_21X000000001333E_20X-SUD-STROUM-M_20180807_000026404801.txt')
    for i in range(210436):
        if i > 8940:
            break
    print(sg.next())

Чтобы понять, как выглядит файл, вот его выдержка:

UNB+UNOC:3+21X000000001333E:020+20X-SUD-STROUM-M:020+180807:1400+000026404801++TL'UNH+000026404802+MSCONS:D:04B:UN:1.0'BGM+7+000026404802+9'DTM+137:201808071400:203'RFF+AGI:6HYR67925RZUD_000000257860_00_E27'NAD+MS+21X000000001333E::020'NAD+MR+20X-SUD-STROUM-M::020'UNS+D'NAD+DP'LOC+172+LU0000010496200000000000050287886::89'DTM+163:201701010000?+01:303'DTM+164:201702010000?+01:303'LIN+1'PIA+5+1-1?:1.29.0:SRW'QTY+220:9.600'DTM+163:201701010000?+01:303'DTM+164:201701010015?+01:303'QTY+220:10.400'DTM+163:201701010015?+01:303'DTM+164:201701010030?+01:303'QTY+220:10.400'DTM+163:201701010030?+01:303'DTM+164:201701010045?+01:303'QTY+220:10.400'DTM+163:201701010045?+01:303'DTM+164:201701010100?+01:303'QTY+220:10.400'DTM+163:201701010100?+01:303'DTM+164:201701010115?+01:303'QTY+220:10.400'DTM+163:201701010115?+01:303'DTM+164:201701010130?+01:303'QTY+220:10.400'DTM+163:201701010130?+01:303'DTM+164:201701010145?+01:303'QTY+220:10.400'DTM+163:201701010145?+01:303'DTM+164:201701010200?+01:303'QTY+220:11.200'DTM+163:201701010200?+01:303' ...

Файл, с которым у меня проблема, имеет 210000 изэти сегменты.Я проверил код и все работает отлично.Список сегментов завершен, и я получаю один сегмент за другим правильно до конца списка.

Я использую сегменты в качестве входных данных для машины состояний, которая получает новые сегменты от экземпляра SegmentGenerator.

Вот выдержка:

    def DTMstarttransition(self,segment):
    match=re.search('DTM\+(.*?):(.*?):(.*?)($|\+.*|:.*)',segment)
    if match:
        if match.group(1) == '164':
            self.currentendtime=self.dateConvert(match.group(2),match.group(3))
            return('DTMend',self.sg.next())
    return('Error',segment + "\nExpected DTM segment didn't match")

Метод возвращает имя следующего состояния и следующего сегмента sg.next (), sg является экземпляром SegmentGenerator.

Однако в8942-й сегмент вызов sg.next () не дает мне следующий сегмент, но второй последний из списка сегментов!

Я проследил вызовы функций (с модулем автолога):

TRACE:segmentgenerator.SegmentGenerator:next:CALL *() **{}
TRACE:segmentgenerator.SegmentGenerator:next:RETURN 'DTM+164:201702010000?+01:303'
TRACE:__main__.MSCONSparser:QTYtransition:RETURN ('DTMstart', 'DTM+164:201702010000?+01:303')
TRACE:__main__.MSCONSparser:DTMstarttransition:CALL *('DTM+164:201702010000?+01:303',) **{}
TRACE:__main__.MSCONSparser:dateConvert:CALL *('201702010000?+01', '303') **{}
TRACE:__main__.MSCONSparser:dateConvert:RETURN datetime.datetime(2017, 2, 1, 0, 0)
TRACE:segmentgenerator.SegmentGenerator:next:CALL *() **{}
TRACE:segmentgenerator.SegmentGenerator:next:RETURN 'UNT+17872+000026404802'
TRACE:__main__.MSCONSparser:DTMstarttransition:RETURN ('DTMend', 'UNT+17872+000026404802')
TRACE:__main__.MSCONSparser:DTMendtransition:CALL *('UNT+17872+000026404802',) **{}

UNT + ... это не следующий сегмент, это должен быть сегмент LIN.Но как это возможно?Почему SegmentGenerator работает, когда я тестирую его с главной функцией в своем модуле и не работает правильно после тысяч вызовов из другого модуля?

Все сегменты находятся там от начала до конца.Я могу проверить это из интерпретатора, так как список sg.segments остается доступным после остановки программы.len (sg.se сегментов) - 210435, но моя программа останавливается после 8942. Так что это явно проблема с итератором.

Файлы (3 файла Python и пример данных) можно найти на Github в ветке 'next', если вы хотите протестировать все это.

Ответы [ 2 ]

0 голосов
/ 26 сентября 2018

Оказалось, что сегмент 'DTM + 164: 201702010000? +01: 303' существует второй раз дальше в файле и что за ним действительно следует сегмент UTM.Так что проблема в самих состояниях протокола, и итератор работал правильно.Мне так жаль, что я обеспокоил вас своим неправильным предположением.Спасибо за желание помочь!

0 голосов
/ 24 сентября 2018

Я думаю, что возможно в вашем файле данных есть двойной апостроф, около 8942-го апострофа.

В этом случае ваш код продолжит читать весь файл, читая все 210435 сегментов.

Но если у вас есть условие, которое проверяет результат sg.next(), то это будет ошибкой на 8942-й итерации, и я предполагаю, что это приводит к прерыванию вашей программы.

Например:

while sg.next():
   # some processing here

Если я полностью ошибаюсь, мне было бы интересно посмотреть на поведение этого: - где len и итерации должны равняться.

if __name__ == '__main__':
    fn = sys.argv[1]
    sg = SegmentGenerator(fn)

    print("Num segments:", len(sg.segments))
    i = 0
    value = 'x'
    while value:
        value = sg.next()
        i += 1
        print(i, value)

    print("Num iterations:", i)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...