Casimir和Hippolyte已经给出了一些好的解决方案。我想详细说明一些事情。
首先,为什么你的正则表达式无法实现你想要的功能:
(?<=<HDR>).*?
告诉它匹配任意数量的字符,从第一个以
<HDR>
为前缀的字符开始,直到遇到非贪婪量词(
<DTL1...
)后面的内容。好吧,第一个以
<HDR>
为前缀的字符是第一个
a
,所以它匹配从那里开始的所有内容,直到遇到固定字符串
<DTL1\sval="3"
。
Casimir和Hippolyte的解决方案适用于广义情况,其中标记的内容可以是除嵌套之外的任何内容。您还可以使用正向查找:
(?<=<HDR>)(.(?!</HDR>))*<DTL1\sval="3".*?</HDR>
然而,如果可以保证字符串的结构如所示,其中<HDR>标记仅包含一个或多个<DTL1 val="
##">标记,因此您知道其中不会有任何闭合标记,您可以通过将第一个
.*?
替换为
[^/]*
来更有效地完成操作。
(?<=<HDR>)[^/]*<DTL1\sval="3".*?</HDR>
一种否定的字符类比零宽断言更有效,而且如果您使用否定的字符类,则贪婪量词比懒惰量词更有效。
还要注意,通过使用回顾后发匹配开头的 <HDR>,您将其从匹配中排除,但是包括结束标记 </HDR>。您确定这是您想要的吗?您正在匹配以下内容...
<DTL1 val="3"><DTL2 val="4"></HDR>
"...当你大概想要这个..."
<HDR><DTL1 val="3"><DTL2 val="4"></HDR>
...或者这个...
<DTL1 val="3"><DTL2 val="4">
因此,在第一种情况下,不要使用前置断言来匹配开标签:
<HDR>(.(?!</HDR>))*<DTL1\sval="3".*?</HDR>
<HDR>[^/]*<DTL1\sval="3".*?</HDR>
在第二种情况下,使用向前查找来查找闭合标签:
(?<=<HDR>)(.(?!</HDR>))*<DTL1\sval="3".*?(?=</HDR>)
(?<=<HDR>)[^/]*<DTL1\sval="3".*?(?=</HDR>)