Подтвердить что ты не робот

Java.lang.StackOverflowError при использовании RegEx для синтаксического анализа больших строк

Это мое 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)

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

Ответ 3

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

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

Совершенно другая альтернатива заключается в том, чтобы написать полезный метод, называемый 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.