问题描述
作为解码通信协议(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的实例。
但是,在8942st段上,调用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”分支中找到文件(3个python文件和数据示例)。
1楼
我认为您的数据文件中第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)
2楼
事实证明,文件'DTM + 164:201702010000?+01:303'中第二次出现了该文件,并且确实存在一个UTM段。 因此问题出在协议状态本身,并且迭代器正常工作。 非常抱歉,我以错误的假设打扰了您。 感谢您的帮助!