如何使用 REGEX 匹配另一个模式之前最后一次出现的模式
How do I match the last occurrence of Pattern before another Pattern with REGEX
我有一个巨大的 XML 文件,我需要提取包含一系列数字的整个标签的内容。
在我的文件中所有内容都是一行,我在此处添加了换行符以使其更具可读性
所以这里我有一个简化的例子
文件:
<ORDERS>
<IDOC BEGIN><tag1>aaa</tag1><tag2>bbb</tag2><tag3>12345</tag3><tag4>ccc</tag4></IDOC>
<IDOC BEGIN><tag1>aaa</tag1><tag2>bbb</tag2><tag3>23456</tag3><tag4>ccc</tag4></IDOC>
<IDOC BEGIN><tag1>aaa</tag1><tag2>bbb</tag2><tag3>0007537181</tag3><tag4>ccc</tag4></IDOC>
<IDOC BEGIN><tag1>aaa</tag1><tag2>bbb</tag2><tag3>34567</tag3><tag4>ccc</tag4></IDOC>
</ORDER>
我想匹配包含序列 0007537181 的 IDOC BEGIN 标签。所以它将是
<IDOC BEGIN><tag1>aaa</tag1><tag2>bbb</tag2><tag3>0007537181</tag3><tag4>ccc</tag4></IDOC>
到目前为止我得到了这个正则表达式:
cat myfile | grep -oP '<IDOC BEGIN.*?0007536846.*?</IDOC>'
结果是从第一个同名标签开始到我想要的标签:
<IDOC BEGIN><tag1>aaa</tag1><tag2>bbb</tag2><tag3>12345</tag3><tag4>ccc</tag4></IDOC>
<IDOC BEGIN><tag1>aaa</tag1><tag2>bbb</tag2><tag3>23456</tag3><tag4>ccc</tag4></IDOC>
<IDOC BEGIN><tag1>aaa</tag1><tag2>bbb</tag2><tag3>0007537181</tag3><tag4>ccc</tag4></IDOC>
我设法通过将其发送到第二个正则表达式来解决这个问题,该正则表达式获取最后一次出现的 IDOC BEGIN
cat myfile | grep -oP '<IDOC BEGIN.*?0007536846.*?</IDOC>' | grep -oP '<IDOC BEGIN(?!.*<IDOC BEGIN).*?</IDOC>'
总而言之,我需要获取数字序列之前的最后一个 IDOC BEGIN
请记住,原始文件没有换行符,所有内容都在一行中。
您可以使用的正则表达式是基于放在开头的贪心点模式,然后是 \K
match reset operator, or based on a 。当涉及到具有部分匹配(但不匹配)的大字符串时,两者都非常不安全。
所以,两个正则表达式是
.*\K<IDOC BEGIN.*?0007536846.*?</IDOC>
<IDOC BEGIN(?:(?!<IDOC BEGIN).)*?0007536846(?:(?!<IDOC BEGIN).)*?</IDOC>
最好的办法是在这些情况下展开经过调整的贪婪令牌:
<IDOC BEGIN[^<]*(?:<(?!IDOC BEGIN)[^<]*?)*0007537181.*?</IDOC>
第一个.*?
替换为[^<]*(?:<(?!IDOC BEGIN)[^<]*?)*
:
[^<]*
- 否定字符 class 匹配除 <
之外的 0 个或更多字符,尽可能多
(?:<(?!IDOC BEGIN)[^<]*?)*
- 0 次或多次重复
<(?!IDOC BEGIN)
- <
字符后没有紧跟着 IDOC BEGIN
字符串
[^<]*?
- 否定字符 class 匹配除 <
之外的 0 个或多个字符,尽可能少
我有一个巨大的 XML 文件,我需要提取包含一系列数字的整个标签的内容。 在我的文件中所有内容都是一行,我在此处添加了换行符以使其更具可读性
所以这里我有一个简化的例子
文件:
<ORDERS>
<IDOC BEGIN><tag1>aaa</tag1><tag2>bbb</tag2><tag3>12345</tag3><tag4>ccc</tag4></IDOC>
<IDOC BEGIN><tag1>aaa</tag1><tag2>bbb</tag2><tag3>23456</tag3><tag4>ccc</tag4></IDOC>
<IDOC BEGIN><tag1>aaa</tag1><tag2>bbb</tag2><tag3>0007537181</tag3><tag4>ccc</tag4></IDOC>
<IDOC BEGIN><tag1>aaa</tag1><tag2>bbb</tag2><tag3>34567</tag3><tag4>ccc</tag4></IDOC>
</ORDER>
我想匹配包含序列 0007537181 的 IDOC BEGIN 标签。所以它将是
<IDOC BEGIN><tag1>aaa</tag1><tag2>bbb</tag2><tag3>0007537181</tag3><tag4>ccc</tag4></IDOC>
到目前为止我得到了这个正则表达式:
cat myfile | grep -oP '<IDOC BEGIN.*?0007536846.*?</IDOC>'
结果是从第一个同名标签开始到我想要的标签:
<IDOC BEGIN><tag1>aaa</tag1><tag2>bbb</tag2><tag3>12345</tag3><tag4>ccc</tag4></IDOC>
<IDOC BEGIN><tag1>aaa</tag1><tag2>bbb</tag2><tag3>23456</tag3><tag4>ccc</tag4></IDOC>
<IDOC BEGIN><tag1>aaa</tag1><tag2>bbb</tag2><tag3>0007537181</tag3><tag4>ccc</tag4></IDOC>
我设法通过将其发送到第二个正则表达式来解决这个问题,该正则表达式获取最后一次出现的 IDOC BEGIN
cat myfile | grep -oP '<IDOC BEGIN.*?0007536846.*?</IDOC>' | grep -oP '<IDOC BEGIN(?!.*<IDOC BEGIN).*?</IDOC>'
总而言之,我需要获取数字序列之前的最后一个 IDOC BEGIN
请记住,原始文件没有换行符,所有内容都在一行中。
您可以使用的正则表达式是基于放在开头的贪心点模式,然后是 \K
match reset operator, or based on a
所以,两个正则表达式是
.*\K<IDOC BEGIN.*?0007536846.*?</IDOC>
<IDOC BEGIN(?:(?!<IDOC BEGIN).)*?0007536846(?:(?!<IDOC BEGIN).)*?</IDOC>
最好的办法是在这些情况下展开经过调整的贪婪令牌:
<IDOC BEGIN[^<]*(?:<(?!IDOC BEGIN)[^<]*?)*0007537181.*?</IDOC>
第一个.*?
替换为[^<]*(?:<(?!IDOC BEGIN)[^<]*?)*
:
[^<]*
- 否定字符 class 匹配除<
之外的 0 个或更多字符,尽可能多(?:<(?!IDOC BEGIN)[^<]*?)*
- 0 次或多次重复<(?!IDOC BEGIN)
-<
字符后没有紧跟着IDOC BEGIN
字符串[^<]*?
- 否定字符 class 匹配除<
之外的 0 个或多个字符,尽可能少