Ruby ruby 正则死循环了怎么破?

ultragtx · 2013年04月09日 · 最后由 luikore 回复于 2013年05月03日 · 3553 次阅读

text = <<TEXT asdf <!-- OPTIONAL : State school colours, using words, then <br>then                                          {{colorbox|#xxyyzz}} TEXT text =~ /<!--(.|\s)*?-->/

一运行就 hang 在那了 1.9.3 2.0.0 都有问题,1.8.7 貌似没事儿

刚才内容被吞了 修改了一下

应该有结束标志吧,--> *是任意多字符,所以没完。

结束标志打掉了?猜想要的正则是

text[/(?<=<!--)((?!-->).)*?(?=-->)/m]

不是结束标志的问题 text 就是一个例子 正常应该返回 nil 但是却 hang 了

改成这样就好了:

text =~ /<!--.*?-->/m

注:并没有死循环,不过匹配的复杂度 NP 了 注:在多行模式里 (m = multiline), . 可以匹配换行符和空格

这跟 NP 有关吗?

#6 楼 @xiongmao86

呃... 是 n power 不是 nondeterministic polynomial problem...

例子可以简化如下 (是否贪婪对是否卡住没影响...):

'-' + ' ' * 41 =~ /-(.|\s)*-/

注意正则最后还要匹配 -, 必须要回溯。选择支的两边 .\s 都匹配空格,所以都在回溯的范围中,这个字符串中有 41 个空格,回溯的深度达到了 41, 要做 2 ** 41 次匹配,于是就 N Power 了 (n 为字符串长度). (这里略过了不少细节... 如果你按照正则的逻辑自己写一个这样的 parser 就会明白了...)

括号里如果用原子组 (?>) 的话,也能避免不必要的回溯:

text =~ /<!--(?>.|\s)*?-->/

还有个修正方法是让选择支两边没有交集:

text =~ /<!--(.|\n)*?-->/
8 楼 已删除

拜楼上 Orz

刚以为 possessive qualifier 可以解决问题兴奋的加了一回复,但实验了一下匹配不了...

#11 楼 @bhuztez re2 功能太弱,光速度快解决不了问题没用啊...

@ultragtx sorry, #8 楼 回的用 *+ 没法匹配,已经删了..

#12 楼 @luikore

Some people, when confronted with a problem, think “I know, I'll use regular expressions.” Now they have two problems.

http://regex.info/blog/2006-09-15/247

#14 楼 @bhuztez learn => abuse => master 是必经之路... 以前被连 java annotation 都不会用的人说滥用 annotation 我就很生气...

需要 登录 后方可回复, 如果你还没有账号请 注册新账号