[英]Java regex dies on stack overflow: need a better version
我工作的一個JMD(Java的降價) (的渣口MarkDownSharp ),但我在遇到一個特別的正則表達式的問題。 對於文件Markdown_Documentation_Syntax.text,這個正則表達式會死掉:
private static final String BLOCK_TAGS_1 = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del";
private static final String BLOCKS_NESTED_PATTERN = String.format("" +
"(" + // save in $1
"^" + // start of line (with MULTILINE)
"<(%s)" + // start tag = $2
"\\b" + // word break
"(.*\\n)*?" + // any number of lines, minimally matching
"</\\2>" + // the matching end tag
"[ \\t]*" + // trailing spaces/tags
"(?=\\n+|\\Z)" + // followed by a newline or end of
")", BLOCK_TAGS_1);
這意味着:
(^<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b(.*\n)*?</\2>[ \t]*(?=\n+|\Z))
此模式正在查找錨定到行開頭的接受塊標記,后跟任意數量的行,然后由匹配標記后跟換行符或字符串終止符終止。 這會產生:
java.lang.StackOverflowError
at java.util.regex.Pattern$Curly.match(Pattern.java:3744)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4168)
at java.util.regex.Pattern$LazyLoop.match(Pattern.java:4357)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4227)
at java.util.regex.Pattern$BmpCharProperty.match(Pattern.java:3366)
at java.util.regex.Pattern$Curly.match0(Pattern.java:3782)
at java.util.regex.Pattern$Curly.match(Pattern.java:3744)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4168)
at java.util.regex.Pattern$LazyLoop.match(Pattern.java:4357)
...
這可以通過增加Java的堆棧空間來處理(默認為oss / ss IIRC的128k / 400k),但無論如何上面的表達式都很慢。
所以我正在尋找能夠做得更好的正則表達大師(或者至少用這種模式解釋性能問題)。 C#版本有點慢,但工作正常。 PHP似乎也沒有問題。
編輯:這是在Windows 7 64 Ultimate上運行的JDK6u17上。
這部分:
(.*\n)*?
因為嵌套*
會涉及很多不必要的回溯,因為之后必須匹配的字符。
我只是在一些任意字符串上運行perl的快速基准測試,只需將該部分切換為13-15%即可
(?>.*\n)*?
這是非捕獲,獨立的子組。 這給你帶來兩個好處,它不再浪費時間捕獲匹配的字符串,更重要的是,它不再在最里面回溯.*
這無論如何浪費時間。 沒有辦法只有那部分。*會產生有效的匹配,所以明確地將它全部或全部都沒有幫助。
但是,不知道在這種情況下這是否足夠改進。
雖然改進模式確實有幫助並且是可取的,但Java的模式匹配器是遞歸的,通常最好切換到迭代解決方案。
當我遇到類似問題時,我切換到jregex( http://jregex.sourceforge.net/ ),這對我有用。
現在使用改進的解決方案可以成功進行模式匹配,但如果給出10倍大的文本,它可能會失敗。
PS:很抱歉有一個老話題,但這個帖子在谷歌上排名很高,如果我把它放在這里會對人們有所幫助
子表達式: "(.*\\\\n)*?"
(以及改進的接受答案版本: "(?>.*\\n)*?"
),都有問題:它們無法匹配寫在一行上的塊元素。 換句話說,他們不符合這個:
<div>one-liner</div>
如果這不是理想的行為,那么正確(並且更有效)的解決方案就是簡單地使用:
.*?
並打開單線模式。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.