来源:
<TD>
<A HREF="/home"><IMG SRC="/images/home.gif"></A>
<IMG SRC="/images/spacer.gif">
<A HREF="/search"><IMG SRC="/images/search.gif"></A>
<IMG SRC="/images/spacer.gif">
<A HREF="/help"><IMG SRC="/images/help.gif"></A>
</TD>
正则表达式:
(<[Aa]\s+[^>]+>\s*)?<[Ii][Mm][Gg]\s+[^>]+>(?(1)\s*</[Aa]>)
结果:
<A HREF="/home"><IMG SRC="/images/home.gif"></A>
<IMG SRC="/images/spacer.gif">
<A HREF="/search"><IMG SRC="/images/search.gif"></A>
<IMG SRC="/images/spacer.gif">
<A HREF="/help"><IMG SRC="/images/help.gif"></A>
什么是“?(1)”是什么意思?
当我在Java中运行它时,它会导致异常:java.util.regex.PatternSyntaxException, “?(1)”无法识别。
书中的解释是:
This pattern requires explanation. (<[Aa]\s+[^>]+>\s*)? matches an opening <A> or <a> tag (with any attributes that may be present), if present (the closing ? makes the expression optional). <[Ii][Mm][Gg]\s+[^>]+> then matches the <IMG> tag (regardless of case) with any of its attributes. (?(1)\s*</[Aa]>) starts off with a condition: ?(1) means execute only what comes next if backreference 1 (the opening <A> tag) exists (or in other words, execute only what comes next if the first <A> match was successful). If (1) exists, then \s*</[Aa]> matches any trailing whitespace followed by the closing </A> tag.
答案 0 :(得分:3)
语法正确。奇怪的外观(?....)设置了条件。这是if ... then语句的正则表达式语法。 (1)是在正则表达式开始时对捕获组的反向引用,其匹配html&lt; a&gt;。 tag,如果有,则该捕获组是可选的。由于对捕获的标签的反向引用遵循正则表达式的“if”部分,因此它正在做的是确保存在开口&lt; a&gt;。在尝试匹配结束标记之前捕获的标记。一种非常聪明的方法,可以使两个标签都是可选的,但是当第一个标签存在时强制它们。这就是它能够匹配示例文本中所有行的方式,即使其中一些只是&lt; img&gt;标签
至于为什么它会在你的情况下抛出异常,很可能你正在使用的正则表达式的味道不支持条件。并非所有人都这样做。
编辑:这是关于正则表达式中条件的一个很好的参考:http://www.regular-expressions.info/conditional.html
答案 1 :(得分:3)
正如Bryan所说,你所看到的是一个条件结构,Java并不支持它们。紧跟在问号之后的带括号的表达式实际上可以是任何零宽度断言,如前瞻或后瞻,而不仅仅是对捕获组的引用。 (我更喜欢称那些 back-assertions ,以避免混淆。 back-reference 与捕获组所做的相同,但是一个后断言断言只是断言捕获组匹配某事。)
几年前我在Perl工作时学习了条件语,但我从未在Java中错过它们。在这种情况下,例如,一个简单的替换将成功:
(?i)<a\s+[^>]+>\s*<img\s+[^>]+>\s*</a]>|<img\s+[^>]+>
条件版本的一个优点是您可以使用单个捕获组捕获IMG标记:
(?i)(<a\s+[^>]+>\s*)?(<img\s+[^>]+>)(?(1)\s*</a>)
在交替版本中,你必须为每个替代版本都有一个捕获组,但这在Java中并不像在Perl中那么重要,它具有所有内置的正则表达式魔法。以下是我在Java中使用IMG标记的方法:
Pattern p = Pattern.compile(
"<a\\s+[^>]+>\\s*(<img\\s+[^>]+>)\\s*</a>|(<img\\s+[^>]+>)"
Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(s);
while (m.find())
{
System.out.println(m.start(1) != -1 ? m.group(1) : m.group(2));
}
答案 2 :(得分:1)
这可能是非捕获组,如下所述:
还有一个特殊的小组,小组 0,总是代表整个 表达。该组不包括在内 在groupCount报告的总数中。 以(?开头的群组是纯粹的, 不捕获的非捕获组 捕获文本,不要指望 小组总数。 (你会看到例子 非捕获组的后期 section模式类的方法。)
答案 3 :(得分:1)
简短的回答:这并不意味着什么。问题在于整个片段:
(?(1)\s*)
()会创建一个后引用,因此您可以重复使用内部匹配的任何文本。它们还允许您将运算符应用于它们内部的所有内容(但在您的示例中没有这样做)。
?意味着它之前的项目应匹配,如果它在那里,但如果不是则也可以。当它出现在(
之后)时,这根本没有意义(?: MoreTextHere ) 当您不需要重用匹配的文本时,可用于加速RegEx。但这仍然没有意义,为什么当你的输入是HTML时匹配1?
尝试:
(?:<[Aa]\s+[^>]+>\s*)?<[Ii][Mm][Gg]\s+[^>]+>
你从未说出你想要匹配的内容,所以如果这个答案不能满足你的要求,请解释你在尝试用RegEx做什么。