Java中的正则表达式运算符似乎总是贪婪

时间:2015-03-13 11:24:26

标签: java regex

我正在尝试从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>继续匹配的任何理由?

2 个答案:

答案 0 :(得分:4)

正如npinti in the comments所解释的,问题是由调用match.match()引起的。这会尝试将您的模式与整个输入字符串进行匹配。只有当正则表达式引擎找到某种方式将字符串表示为模式的实例时,它才会成功。实现此目的的唯一方法是使(.*?)foo</p> <p>bar匹配。

有两种方法可以解决这个问题:

  1. 最简单的方法是切换到match.find()。这会在字符串中找到您的模式的第一个匹配项。由于不需要匹配整个字符串,因此非贪心量词可确保您根据需要获得foo

  2. 调整模式以匹配整个字符串。即"<p(?: [^>]*)?>(.*?)</p>.*"


  3. 然而,

    不可避免地,这些“简单”的计划要解析一些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