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)
Как это вызвано и как я могу его решить?
Ответы
Ответ 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.