Python Iterator奇怪地跳过了项目

时间:2018-09-24 10:56:11

标签: python iterator

作为解码通信协议(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分段。 但这怎么可能呢?为什么我在其模块中的main函数对其进行测试时,SegmentGenerator可以工作,而在另一个模块进行数千次调用后却无法正常工作?

所有段从头到尾都在那里。我可以从解释器验证这一点,因为程序停止后,列表sg.segments仍然可用。 len(sg.segments)是210435,但是我的程序在8942之后停止。因此,显然迭代器存在问题。

如果要测试整个文件,可以在分支“ next”的Github上找到文件(3个python文件和数据示例)。

2 个答案:

答案 0 :(得分:0)

我认为您的数据文件中第8942个撇号附近可能有一个双撇号

在这种情况下,您的代码将继续读取读取所有210435段的整个文件。

但是如果您有条件测试kwargs的结果,那么在第8942次迭代中这将是错误的,而且我猜想这会导致您的程序中止。

例如:

sg.next()

如果我完全错了,那么我很想看看它的行为:-len和迭代次数应该相等。

while sg.next():
   # some processing here

答案 1 :(得分:0)

事实证明,文件'DTM + 164:201702010000?+01:303'的段第二次出现在文件的更下方,并且确实存在一个UTM段。因此问题出在协议状态本身,并且迭代器正常工作。 非常抱歉,我以错误的假设打扰了您。感谢您的帮助!