java.lang.StackOverflowError при использовании RegEx для разбора больших строк - PullRequest
33 голосов
/ 22 сентября 2011

Это мой Regex

((?:(?:'[^']*')|[^;])*)[;]

Он разбивает строку на точки с запятой. Например,

Hello world; I am having a problem; using regex;

Результат - три строки

Hello world
I am having a problem
using regex

Но когда я использую большую строку ввода, я получаю эту ошибку

Exception in thread "main" java.lang.StackOverflowError
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4168)
at java.util.regex.Pattern$Loop.match(Pattern.java:4295)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4227)
at java.util.regex.Pattern$BranchConn.match(Pattern.java:4078)
at java.util.regex.Pattern$CharProperty.match(Pattern.java:3345)
at java.util.regex.Pattern$Branch.match(Pattern.java:4114)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4168)
at java.util.regex.Pattern$Loop.match(Pattern.java:4295)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4227)

Как это вызвано и как я могу решить?

Ответы [ 3 ]

52 голосов
/ 22 сентября 2011

К сожалению, встроенная поддержка регулярных выражений в Java имеет проблемы с регулярными выражениями, содержащими повторяющиеся альтернативные пути (то есть (A|B)*).Это скомпилировано в рекурсивный вызов, который приводит к ошибке StackOverflow при использовании на очень большой строке.

Возможное решение состоит в том, чтобы переписать ваше регулярное выражение, чтобы не использовать повторяющуюся альтернативу, но если ваша цель состоит в том, чтобы разбить строку на точки с запятой, вам вообще не нужно сложное регулярное выражение, просто используйте String.split () с простым ";" в качестве аргумента.

15 голосов
/ 23 мая 2014

Если вам действительно нужно использовать регулярное выражение, которое переполняет ваш стек, вы можете увеличить размер своего стека, передав в JVM нечто вроде -Xss40m.

6 голосов
/ 06 октября 2011

Может быть полезно добавить + после [^;], чтобы у вас было меньше повторений.

Не существует ли какой-либо конструкции, которая говорит: «Если регулярное выражение соответствует этой точке, не возвращаться»? Может быть, это тоже пригодится. (Обновление: оно называется притяжательные квантификаторы ).

Совершенно другой альтернативой является написание вспомогательного метода с именем splitQuoted(char quote, char separator, CharSequence s), который явно перебирает строку и запоминает, видел ли он нечетное количество кавычек. В этом методе вы также можете обрабатывать случай, когда символ кавычки может потребоваться экранировать, когда он появляется в строке в кавычках.

'I'm what I am', said the fox; and he disappeared.
'I\'m what I am', said the fox; and he disappeared.
'I''m what I am', said the fox; and he disappeared.
...