过去两天我一直试图解决这个问题......
请帮助我理解为什么会这样。我的目的是只选择<HDR>
<DTL1 val="92">.....</HDR>
这是我的正则表达式
(?<=<HDR>).*?<DTL1\sval="3".*?</HDR>
输入字符串是:
<HDR>abc<DTL1 val="1"><DTL2 val="2"></HDR><HDR><DTL1 val="92"><DTL2 val="55"></HDR><HDR><DTL1 val="3"><DTL2 val="4"></HDR>
但是这个正则表达式选择了
abc<DTL1 val="1"><DTL2 val="2"></HDR><HDR><DTL1 val="92"><DTL2 val="55"></HDR>
有人可以帮助我吗?
答案 0 :(得分:2)
正则表达式引擎将始终为您提供字符串中最左侧的匹配(即使您使用非贪婪的量词)。这正是您获得的。
因此,一个解决方案是禁止在<HDR>
描述的部分中存在另一个.*?
太过宽松。
您有两种技术要做,您可以将.*?
替换为:
(?>[^<]+|<(?!/HDR))*
或与:
(?:(?!</HDR).)*+
大多数情况下,第一种技术性能更高,但如果你的字符串包含高密度的<
,第二种方法也可以产生良好的效果。
使用possessive quantifier或atomic group可以减少获取结果的步骤数,特别是在子模式失败时。
示例:
第一种方式:
(?<=<HDR>)(?>[^<]+|<(?!/HDR))*<DTL1\sval="3"(?>[^<]+|<(?!/HDR))*</HDR>
或此变体:
(?<=<HDR>)(?:[^<]+|<(?!/HDR|DTL1))*+<DTL1\sval="3"(?:[^<]+|<(?!/HDR))*+</HDR>
第二种方式:
(?<=<HDR>)(?:(?!</HDR).)*<DTL1\sval="3"(?:(?!</HDR).)*+</HDR>
或此变体:
(?<=<HDR>)(?:(?!</HDR|DTL1).)*+<DTL1\sval="3"(?:(?!</HDR).)*+</HDR>
答案 1 :(得分:1)
Casimir et Hippolyte已经为您提供了几个很好的解决方案。我想详细说明一些事情。
首先,为什么你的正则表达式无法做你想做的事情:(?<=<HDR>).*?
告诉它匹配以<HDR>
开头的第一个字符开头的任意数量的字符,直到遇到非贪婪之后的字符量词(<DTL1...
)。好吧,<HDR>
前面的第一个字符是第一个a
,所以它匹配从那里开始的所有字符,直到遇到固定字符串<DTL1\sval="3"
。
Casimir et Hippolyte的解决方案是针对一般情况的,其中&lt; HDR&gt;的内容是&lt; HDR&gt;。标签可以是嵌套&lt; HDR&gt;以外的任何其他内容。你也可以积极地展望:
(?<=<HDR>)(.(?!</HDR>))*<DTL1\sval="3".*?</HDR>
但是,如果保证字符串在所示结构中,则&lt; HDR&gt;标签只包含一个或多个&lt; DTL1 val =&#34; ## &#34;&gt;标签,因此您知道其中没有任何结束标记,您可以通过将.*?
替换为[^/]*
来更有效地执行此操作:
(?<=<HDR>)[^/]*<DTL1\sval="3".*?</HDR>
否定字符类比零宽度断言更有效,而如果你使用否定字符类,贪婪量词变得比懒惰更有效。
另请注意,通过使用lookbehind匹配开头&lt; HDR&gt;,您可以将其从匹配中排除,但是您还要包括结束&lt; / HDR&gt;。你确定这是你想要的吗?你匹配这个...
<DTL1 val="3"><DTL2 val="4"></HDR>
......大概你想要这个......
<HDR><DTL1 val="3"><DTL2 val="4"></HDR>
......或者......
<DTL1 val="3"><DTL2 val="4">
所以,在第一种情况下,不要使用lookbehind作为开头标记:
<HDR>(.(?!</HDR>))*<DTL1\sval="3".*?</HDR>
<HDR>[^/]*<DTL1\sval="3".*?</HDR>
在第二种情况下,使用结束标记的前瞻:
(?<=<HDR>)(.(?!</HDR>))*<DTL1\sval="3".*?(?=</HDR>)
(?<=<HDR>)[^/]*<DTL1\sval="3".*?(?=</HDR>)