我有一些针对很长字符串运行的正则表达式。然而,关于RE的字符串的唯一部分接近开头。大多数RE类似于:
\\s+?(\\w+?).*
RE在开始附近捕获几个组,并不关心字符串的其余部分。出于性能原因,有没有办法让RE引擎避免查看终止.*
所消耗的所有字符?
注意:带有RE的应用程序是使用java.regex
类编写的。
编辑:例如,我有以下RE:
.*?id="number"[^>]*?>([^<]+?).*
针对存储为StringBuilder
s的大型HTML文件运行。 id="number"
标记始终位于HTML文件的开头。
答案 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有关于占有量词的教程信息。