是否可以将正则表达式快捷方式匹配?

时间:2009-08-03 00:59:20

标签: java regex performance optimization

我有一些针对很长字符串运行的正则表达式。然而,关于RE的字符串的唯一部分接近开头。大多数RE类似于:

\\s+?(\\w+?).*

RE在开始附近捕获几个组,并不关心字符串的其余部分。出于性能原因,有没有办法让RE引擎避免查看终止.*所消耗的所有字符?

注意:带有RE的应用程序是使用java.regex类编写的。

编辑:例如,我有以下RE:

.*?id="number"[^>]*?>([^<]+?).*

针对存储为StringBuilder s的大型HTML文件运行。 id="number"标记始终位于HTML文件的开头。

6 个答案:

答案 0 :(得分:6)

使用java.util.regex类时,有许多方法可以匹配给定的字符串。 Matcher.matches始终与整个输入字符串匹配。 Matcher.find在输入字符串中找到与正则表达式匹配的内容。最后,Matcher.lookingAt会将您的正则表达式与输入字符串的开头进行匹配。

如果您使用的是Matcher.matches,则可能需要最后的.*来匹配整个字符串。但是,您可能最好使用其他方法之一,这样您就可以放弃.*。听起来Matcher.lookingAt可能适合您的目的。

答案 1 :(得分:2)

为什么不拿出。* ,你不需要它。

^\\s+?(\\w+?)

答案 2 :(得分:1)

.*?id="number"[^>]*?>([^<]+?).*

这真的是你正在使用的正则表达式吗?我问的原因是因为([^<]+?)总是会匹配一个字符,就像你写了([^<])一样。 +量词必须至少匹配一次,但由于它不情愿,它会立即切换到下一部分 - .* - 它总是成功。删除.*并切换到find()lookingAt()也不会改变该行为(尽管获得相同结果可能会更快一些)。如果要将所有文本匹配到下一个尖括号,您应该删除问号:([^<]+)

[^>]*?>也没有多大意义。在匹配括号之前,你必须使用尽可能多的非括号,那么使量词不情愿的是什么呢?事实上,也没有必要让它变得贪婪;如果[^>]*匹配尽可能多,而下一个字符不是'&gt;',则表示回溯不会有任何好处。如果你的正则表达式支持它们,你也可以使用占有量词 - [^>]*+> - 或原子组 - (?>[^>]*+)>

第一个量化部分 - .*? - 是唯一正确使用的部分(如果不是最佳的话)。将其放在正则表达式的开头会模拟find()在您使用lookingAt()或(最后使用.*matches()时的行为。但是,正如您所发现的那样,将其关闭并使用find()会更有效率。

不情愿的量词非常方便,但最近似乎他们已经过度曝光了。随着频率的增加,我看到人们给出了“使用不情愿的量词”的建议,没有任何解释或资格 - 只是另一个银弹。而且我相信这个问题中的正则表达式就是结果。在三个不情愿的量词中,一个应该是贪婪的,一个应该是占有欲的,另一个根本不应该存在。

编辑:这是一个例子来说明我正在谈论的一些内容,并解决斯蒂芬C的评论。鉴于此字符串:

<div id="number" class="whatever">abc123</div>

......正则表达式的动态部分匹配如下:

.*?         => '<div '

[^>]*?      => ' class="whatever"'

([^<]+?)    => 'a'

.*          => 'bc123</div>'

将所有不情愿的量词更改为贪婪并不会改变整体匹配(整个字符串),也不会改变前两个动态部分匹配的内容。但最后两个被重新分配:

([^<]+)     => 'abc123'

.*          => '</div>'

看看原始的正则表达式,我认为这一定是理想的结果;如果不捕获整个内容,为什么在捕获组中使用这样复杂的子表达式'abc123'?这就是让我相信那些不情愿的量词被盲目地用作灵丹妙药的原因。

另一件事:回顾一下这个帖子,我看到OP实际上并没有当他切换到{时,他已从正则表达式的前面删除了.*? {1}}方法。 @Ben,如果你还没有这样做,你应该;现在只是放慢了速度。那会让你留下这个正则表达式:

find()

我也不希望任何人认为我正在接受已接受的答案。我只是抓着这个痒我对过度使用或不恰当使用不情愿的量词。

答案 3 :(得分:0)

如果您正在处理HTML,除非您对数据文件有100%的控制权,否则正则表达式不是进行分析的正确工具。它最终会破裂。

在我看来,你需要id =“number”的标签内容,而且显然也是如此。存在允许对HTML输入进行XSLT转换的宽松解析器,这可能正是您所需要的。如果你有兴趣,我会查阅。

答案 4 :(得分:0)

有一个很棒的库来处理HTML文件 - 包括格式错误的现实世界:BeautifulSoup http://www.crummy.com/software/BeautifulSoup/

使用此库找到您的id =标签非常容易

答案 5 :(得分:0)

在这种情况下,特殊情况下,简单的答案是使用'find'而不是'matches'。但是,如果这对您不起作用,Java Pattern类支持具有所谓占有量词的正则表达式,可用于防止回溯。

占有量词是贪婪和不情愿量词的第三种选择。 Java中的语法是'X?+'或'X * +'或'X ++'。占有量词匹配尽可能多的字符(如贪婪量词),但如果模式的其余部分不匹配,则占有量词会失败而不是后退。 (有点像Prolog中的“cut”。)

但请注意,使用占有量词而不是贪婪或不情愿的量词会改变你的模式的含义。

this page有关于占有量词的教程信息。