我正在尝试从HTML代码段中获取第一段内容......没什么比这更容易了,是吧?但出于某种原因,.*?
运营商似乎贪婪:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test
{
public static void main(String[] args)
{
Pattern regex = Pattern.compile("<p(?: [^>]*)?>(.*?)</p>", Pattern.DOTALL);
Matcher match = regex.matcher("<p class=\"baz\">foo</p> <p>bar</p>");
System.out.println(match.matches());
System.out.println(match.group(1));
}
}
我希望只匹配第一段(foo
)的内容,但结果如下:
$ javac test.java && java test
true
foo</p> <p>bar
.*?
之后</p>
继续匹配的任何理由?
答案 0 :(得分:4)
正如npinti in the comments所解释的,问题是由调用match.match()
引起的。这会尝试将您的模式与整个输入字符串进行匹配。只有当正则表达式引擎找到某种方式将字符串表示为模式的实例时,它才会成功。实现此目的的唯一方法是使(.*?)
与foo</p> <p>bar
匹配。
有两种方法可以解决这个问题:
最简单的方法是切换到match.find()
。这会在字符串中找到您的模式的第一个匹配项。由于不需要匹配整个字符串,因此非贪心量词可确保您根据需要获得foo
。
调整模式以匹配整个字符串。即"<p(?: [^>]*)?>(.*?)</p>.*"
。
不可避免地,这些“简单”的计划要解析一些HTML grow more and more unwieldy as requirements change。用JSoup之类的东西解析HTML真的很简单。切换到现在,不要回头看。看看它有多容易:
Document doc = Jsoup.parseBodyFragment("<p class=\"baz\">foo</p> <p>bar</p>");
Elements paragraphs = doc.getElementsByTag("p");
if (paragraphs.size() > 0) {
System.out.println(paragraphs.get(0).text());
}
打印:foo
。
答案 1 :(得分:3)
很抱歉没有发布此版本,因此无法访问Java环境。
问题是matches()
会尝试匹配整个字符串。这意味着它将隐式添加^
和$
。用matches()
替换find()
可以解决问题:
Pattern regex = Pattern.compile("<p(?: [^>]*)?>(.*?)</p>", Pattern.DOTALL);
Matcher match = regex.matcher("<p class=\"baz\">foo</p> <p>bar</p>");
System.out.println(match.find());
System.out.println(match.group(1));
收率:
true
foo