在Java中使用Matcher和Pattern对象的问题

时间:2010-12-09 23:01:39

标签: java regex posix

我正在尝试制作一个Lexer。我正在使用Matcher对象从HTML字符串中获取下一个标记。我试图使用Matcher的lookingAt()方法来获得我正在寻找的POSIX表达式的第一次出现。问题是group()应该只打印出与表达式匹配的短语,而是打印出整个HTML字符串。这是代码:

public static final String[] DEFAULT_RULES = new String[] {         
            // PUT YOUR REGULAR EXPRESSIONS HERE.  SEE THE ORDER BELOW
            "<!--.*-->",                                    // A comment TESTED
            "<\\p{Alnum}+.*\\p{Blank}*/>",                  // Singular Tag
            "<\\p{Alnum}+.*[^/]*>",                         // Opening Tag TESTED
            "</\\p{Alnum}+\\p{Space}*>",                    // Closing Tag TESTED
            "&.*;",                                         // HTTP Entity TESTED
            ".*"    };

方法:

    for( int i = 0; i < DEFAULT_RULES.length; i++ ) {// Loop through each expression and try to find a matching phrase
        pattern = Pattern.compile( DEFAULT_RULES[i], Pattern.DOTALL );  // Get a Regex Pattern
        matcher = pattern.matcher( mainString );    // Check if Pattern matches the String

        //matcher.region( position, mainString.length() );  // Make the Region start from the current pointer to the end

        if( matcher.lookingAt() ) {     // Match found at current position
            int s = matcher.start();
            int e = matcher.end();
            String nextToken = matcher.group();     // Save the current phrase that matched the expression
            position = matcher.end();           // Move position pointer to the character after the end of the Token
            return nextToken;// return the Token
        }
    }

注意: DEFAULT_RULES是我要查找的表达式字符串列表。我期待的输出是:

<P>

但我获得了整个HTML文件。我希望这是有道理的。

3 个答案:

答案 0 :(得分:1)

组索引0始终是整个匹配字符串。索引1+返回各个组。所以

字符串:abc

正则表达式:。*(b)。*

第0组:abc

第1组:b

答案 1 :(得分:1)

您的正则表达式可能与整个文档匹配,而不仅仅是<P>标记。这可能是由于贪婪的匹配。如果你正在使用这样的东西:

<P.*>

你可能最好按照

的方式修改它
<P.*?>

<P[^>]*>

请参阅此页面上的“不情愿的量词”部分:http://download.oracle.com/javase/1.4.2/docs/api/java/util/regex/Pattern.html

答案 2 :(得分:1)

lookingAt()将正则表达式应用为\A的开头,因此您将获得的唯一匹配就是从主题的开头开始的匹配。如果主题不是<&,则该列表中唯一匹配的正则表达式是最后一个.*。而且,由于您在DOTALL模式下进行匹配,.*将始终与整个主题匹配。

看起来你打算在每场比赛后更新比赛开始位置,我看到你保存新位置,但你从不做任何事情。您需要在region(int, int)方法中使用它来更改Matcher认为的主题的开头,如下所示:

position = matcher.end();
matcher.region(position, matcher.regionEnd());

但是由于大多数正则表达式中.*,所有这些都在DOTALL模式下应用,因此每场比赛你仍然会得到比你想要的更多的东西。你需要比这更具体。 具体取决于您的最终目标。如果您正在尝试为完整的,工业级的HTML解析器编写词法分析器,那么现在应该放弃它,并阅读如何编写真正的解析器。

Here's来自Mastering Regular Expressions的代码列表与您正在执行的操作类似。它演示了一些重要的技术,例如将正则表达式保存为已编译的Pattern对象,并使用Matcher的usePattern()方法将其交换出来,而不是不断创建新的Pattern和Matcher对象。 (他还为每个正则表达式添加\\G并使用find()find(int)来应用它们;该部分已过时。region()lookingAt()就是您所需要的。)