需要 REGEX 帮助返回关键字之间的多行
Need REGEX help returning multiple lines between keywords
纠结了两天终于敢问了
这是我的数据(文件):
EXH;2;20180514103023+00;
TSH;FI__REPLACEMGA_LOS_92_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_92_12345;;;;;;LOS_92_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSH;FI__REPLACEMGA_LOS_93_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_93_12345;;;;;;LOS_93_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSV;4;201805120300+00;0.000000;Z01;
TSH;FI__REPLACEMGA_LOS_96_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_96_12345;;;;;;LOS_96_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSV;4;201805120300+00;0.000000;Z01;
TSH;FI__REPLACEMGA_LOS_97_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_97_12345;;;;;;LOS_97_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSV;4;201805120300+00;0.000000;Z01;
EXT;
我想从正则表达式中得到 4 个块(4 个匹配项),例如:
TSH;FI__REPLACEMGA_LOS_92_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_92_12345;;;;;;LOS_92_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
在每场比赛中,我将进一步应用一些正则表达式。但是现在,我无法为 return 那些匹配项制作正则表达式。
这是我尝试过的:
(TSH;FI(?:.*?\r?\n?)*(?<=TSH;))+
但是这个 return 仅匹配 2 次(每秒),可能是因为它在匹配后消耗了块的每个 "TSH;"。
(TSH;(?:.*?\r?\n?)*)+(?<=\nTSH;)
这个找到 4 "TSH;" 但不是完整的块。
需要帮助:)
P.S。将用于 Python
您可以使用以下模式:
(?s)^TSH;.*?Z01;(?=\nTSH|\nTSV;4)
(?s)
re.DOTALL
选项。
^TSH;
匹配字符串开头的子字符串 TSH;
。
.*?
懒惰地匹配任何东西。
Z01;
匹配子串 Z01;
.
(?=\nTSH|\nTSV;4)
。 TSH
或 TSV;4
. 的正面前瞻
你可以现场试一下here。
在Python中你可以使用:
print(re.findall(r'^TSH;.*?Z01;(?=\nTSH|\nTSV;4)',mystr,re.DOTALL|re.MULTILINE))
老实说,我根本不会为这项工作使用正则表达式。
似乎更容易拆分 TSH
然后稍后清理它。
所以如果数据在data
,我们可以这样做:
blocks = [ "TSH" + block for block in data.split("TSH") ]
第一个块是假的,所以去掉它:
blocks = blocks[1:]
最后一个块有额外的 "EXT;\n"
,所以也把它清理干净:
blocks = blocks[-1] = blocks[-1][:-len("EXT;\n")]
就是这样,你已经完成了。
当然,这是假设 TSH
不会出现在您的数据中间。如果是这样,您可以按换行符拆分数据,查看哪些行以 TSH
开头,然后使用这些索引来分割您的数据。
这是一个真正令人讨厌的单行代码:
["\n".join(data.split()[i:j]) for i, j in zip(*(lambda a, b: (a, next(b) and b))(*itertools.tee(itertools.chain(( i for i, line in enumerate(data.split()) if line.startswith("TSH")), (len(data.split()),)))))]
再也不敢问是否奋斗再久。我打赌你正在寻找这个:
TSH(?:\n|.)+?(?=\nTSH|\nEXT|\nTSV;4)
Regex101 上的演示和此处的解释:
TSH
很明显,字面上匹配
(?:\n|.)
是一组非捕获字符。因为 .
匹配任何字符(行结束符除外),所以你必须添加一个换行符 \n
.
(?:\n|.)+?
至少匹配上述组中的一个字符
(?=\nTSH|\nEXT|\nTSV;4)
直到达到其中一个终止条件。注意\n
,否则也会匹配空行。
这里是更正后的测试数据:
EXH;2;20180514103023+00;
TSH;FI__REPLACEMGA_LOS_92_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_92_12345;;;;;;LOS_92_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSV;4;201805120300+00;0.000000;Z01;
TSH;FI__REPLACEMGA_LOS_93_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_93_12345;;;;;;LOS_93_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSV;4;201805120300+00;0.000000;Z01;
TSH;FI__REPLACEMGA_LOS_96_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_96_12345;;;;;;LOS_96_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSV;4;201805120300+00;0.000000;Z01;
TSH;FI__REPLACEMGA_LOS_97_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_97_12345;;;;;;LOS_97_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSV;4;201805120300+00;0.000000;Z01;
EXT;
用
这样的表达式
(?s)^TSH;.*?Z01;(?=\nTSH|\nEXT)
我确实得到了匹配,就像我想要 TSH 块一样......记录如下:
TSH;FI__REPLACEMGA_LOS_92_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_92_12345;;;;;;LOS_92_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSV;4;201805120300+00;0.000000;Z01;
非常感谢 UnbearableLightness
纠结了两天终于敢问了
这是我的数据(文件):
EXH;2;20180514103023+00;
TSH;FI__REPLACEMGA_LOS_92_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_92_12345;;;;;;LOS_92_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSH;FI__REPLACEMGA_LOS_93_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_93_12345;;;;;;LOS_93_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSV;4;201805120300+00;0.000000;Z01;
TSH;FI__REPLACEMGA_LOS_96_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_96_12345;;;;;;LOS_96_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSV;4;201805120300+00;0.000000;Z01;
TSH;FI__REPLACEMGA_LOS_97_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_97_12345;;;;;;LOS_97_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSV;4;201805120300+00;0.000000;Z01;
EXT;
我想从正则表达式中得到 4 个块(4 个匹配项),例如:
TSH;FI__REPLACEMGA_LOS_92_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_92_12345;;;;;;LOS_92_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
在每场比赛中,我将进一步应用一些正则表达式。但是现在,我无法为 return 那些匹配项制作正则表达式。
这是我尝试过的:
(TSH;FI(?:.*?\r?\n?)*(?<=TSH;))+
但是这个 return 仅匹配 2 次(每秒),可能是因为它在匹配后消耗了块的每个 "TSH;"。
(TSH;(?:.*?\r?\n?)*)+(?<=\nTSH;)
这个找到 4 "TSH;" 但不是完整的块。
需要帮助:) P.S。将用于 Python
您可以使用以下模式:
(?s)^TSH;.*?Z01;(?=\nTSH|\nTSV;4)
(?s)
re.DOTALL
选项。^TSH;
匹配字符串开头的子字符串TSH;
。.*?
懒惰地匹配任何东西。Z01;
匹配子串Z01;
.(?=\nTSH|\nTSV;4)
。TSH
或TSV;4
. 的正面前瞻
你可以现场试一下here。
在Python中你可以使用:
print(re.findall(r'^TSH;.*?Z01;(?=\nTSH|\nTSV;4)',mystr,re.DOTALL|re.MULTILINE))
老实说,我根本不会为这项工作使用正则表达式。
似乎更容易拆分 TSH
然后稍后清理它。
所以如果数据在data
,我们可以这样做:
blocks = [ "TSH" + block for block in data.split("TSH") ]
第一个块是假的,所以去掉它:
blocks = blocks[1:]
最后一个块有额外的 "EXT;\n"
,所以也把它清理干净:
blocks = blocks[-1] = blocks[-1][:-len("EXT;\n")]
就是这样,你已经完成了。
当然,这是假设 TSH
不会出现在您的数据中间。如果是这样,您可以按换行符拆分数据,查看哪些行以 TSH
开头,然后使用这些索引来分割您的数据。
这是一个真正令人讨厌的单行代码:
["\n".join(data.split()[i:j]) for i, j in zip(*(lambda a, b: (a, next(b) and b))(*itertools.tee(itertools.chain(( i for i, line in enumerate(data.split()) if line.startswith("TSH")), (len(data.split()),)))))]
再也不敢问是否奋斗再久。我打赌你正在寻找这个:
TSH(?:\n|.)+?(?=\nTSH|\nEXT|\nTSV;4)
Regex101 上的演示和此处的解释:
TSH
很明显,字面上匹配(?:\n|.)
是一组非捕获字符。因为.
匹配任何字符(行结束符除外),所以你必须添加一个换行符\n
.(?:\n|.)+?
至少匹配上述组中的一个字符(?=\nTSH|\nEXT|\nTSV;4)
直到达到其中一个终止条件。注意\n
,否则也会匹配空行。
这里是更正后的测试数据:
EXH;2;20180514103023+00;
TSH;FI__REPLACEMGA_LOS_92_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_92_12345;;;;;;LOS_92_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSV;4;201805120300+00;0.000000;Z01;
TSH;FI__REPLACEMGA_LOS_93_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_93_12345;;;;;;LOS_93_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSV;4;201805120300+00;0.000000;Z01;
TSH;FI__REPLACEMGA_LOS_96_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_96_12345;;;;;;LOS_96_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSV;4;201805120300+00;0.000000;Z01;
TSH;FI__REPLACEMGA_LOS_97_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_97_12345;;;;;;LOS_97_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSV;4;201805120300+00;0.000000;Z01;
EXT;
用
这样的表达式(?s)^TSH;.*?Z01;(?=\nTSH|\nEXT)
我确实得到了匹配,就像我想要 TSH 块一样......记录如下:
TSH;FI__REPLACEMGA_LOS_92_12345;1;1;HOUR;kWh;24;201805120000+00;201805130000+00;LOS_92_12345;;;;;;LOS_92_12345;;;
TSV;1;201805120000+00;0.000000;Z01;
TSV;2;201805120100+00;0.000000;Z01;
TSV;3;201805120200+00;0.000000;Z01;
TSV;4;201805120300+00;0.000000;Z01;
非常感谢 UnbearableLightness