优化Java中的正则表达式
Posted gShow
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了优化Java中的正则表达式相关的知识,希望对你有一定的参考价值。
代码1中的正则表达式的目的是匹配html的image标签中的src属性的内容。我特意简化了这个表达式,假定在src之后没有其他属性,这样可以将精力集中到性能上。
这个表达式匹配输入的字符串“string 1”时速度足够快,但是尝试匹配输入字符串“string 2”并宣布失败时花费了很长时间(随着输入字符串的长度成指数增长)。它匹配失败是因为输入字符串结尾没有“/>”。为了优化这个表达式,看一下第一个“.*”结构。它匹配“src”之前的任何属性,但是太普通并且匹配次数太多了。事实上,这个结构应该只匹配除“src”之外的属性。
重写的表达式“<img((?!src=).)*src=(/S*)/>”处理大且不匹配的字符串的速度要比原来的快将近100倍。
为什么不是lazy模式? |
你可能会认为我会使用勉强模式“.*?”优化代码1中的正则表达式。事实上,“<img.*?src=(.*)/>”能够轻易地匹配第一个遇到的“src=”。这个解决方案在该正则表达式可以匹配的时候能够正常工作。如果它不能匹配输入字符串,然而,它将开始回缩,然后消耗和贪婪模式同样长的时间。记住,首先使用不能匹配的字符串测试正则表达式。 |
注意StackOverflowError(A note about the StackOverflowError)
有时regex包中的Pattern类会抛出StackOverflowError。这是已知的bug #5050507的表现,它自从Java 1.4就存在于java.util.regex包中。这个bug仍然存在,因为它是“won't fix”的状态。这个错误的出现是因为,Pattern类把一个正则表达式编译为一个用来寻找匹配的小程序。这个程序被递归调用,有时太多的递归就会导致该错误的出现。更多细节请参考bug描述。看起来大部分是在使用选择(alternation)的出现。
如果你碰到了这个错误,尝试重写正则表达式,或者分为几个子表达式,然后分别单独执行。后者有时设置会提高性能。
总结(In conclusion)
正则表达式不应该花费数小时匹配,特别是应用程序只有几秒时间时。在本文中,我介绍了java.util.regex包的一些弱点,并且向你展示了如何克服这些弱点。像回缩(backtracking)这样的简单瓶颈只需要一些小小的技巧,而像贪婪模式和勉强模式(greedy and reluctant quantifiers)这样的罪魁祸首就需要更加仔细的考虑。在某些情况下,你可以完全替换它们,而在另外一些情况下,可以使用“环视(lookaround)”。无论哪种方式,你已经掌握了一些正则表达式的提升速度的技巧
以上是关于优化Java中的正则表达式的主要内容,如果未能解决你的问题,请参考以下文章