需要 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)TSHTSV;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