Судя по тому, сколько раз java.util.regex.Pattern$LazyLoop.match(...)
появляется в трассировке стека, я держу пари, что проблема заключается в использовании неохотного квантификатора *?
: сначала он ничего не пытается сопоставить, затем он возвращается и пытается соответствует одному символу, затем он возвращается и пытается сопоставить два символа и так далее. Поэтому, если у вас есть длинный комментарий, ему придется много откатываться назад, что, по-видимому, включает в себя рекурсию. (Я не знаю, включает ли все обратное отслеживание рекурсию или просто обратное отслеживание с неохотным квантификатором; фактически, до сих пор я даже не осознавал, что обратное отслеживание с неохотным квантификатором имело место.) Если вы измените эту часть :
/\*(?:.|[\r\n])*?\*/
к этому:
/\*(?:[^*]|\*(?!/))*+\*/
(используя вместо этого собственнический квантификатор *+
- он пытается сопоставить столько, сколько может, и никогда ничего не возвращает), я думаю, вы обнаружите, что обрабатывать длинные комментарии гораздо лучше. Итак, в целом ваш строковый литерал будет выглядеть так:
"/\\*(?:[^*]|\\*(?!/))*+\\*/|\"(?:[^\"\\\\\\r\\n]|\\\\.)*\"|//.*|\\b\\d+\\b|\\b0[xX][\\da-fA-F]+\\b"
Отредактировано, чтобы добавить (июль '13): У кого-то в моей компании недавно возникла похожая проблема, из-за которой я немного углубился в причину. Я обнаружил, что проблема не только в возврате, но и в сочетании возврата с подгруппой; например, a*
или a*?
не будет иметь этой проблемы, но (a)*
или (a)*?
или (?:a)*
или (?:a)*?
. Выше я предложил отключить возврат, используя *+
вместо *?
(и внеся необходимые изменения в подвыражение); но другой подход состоял бы в том, чтобы устранить подвыражение, изменив это:
/\*(?:.|[\r\n])*?\*/
на это:
/\*(?s:.*?)\*/
(где запись (?s:...)
эквивалентна ...
, за исключением того, что она локально включает режим MULTILINE
, что означает, что .
будет соответствовать любому символу, даже \n
). .*?
не требует рекурсии для включения возврата.
Тем не менее, я думаю, что *+
подход лучше в этом случае, и, возможно, в большинстве случаев, поскольку его алгоритмическая временная сложность ниже. (.*?
требует постоянной попытки сопоставления и повторного сопоставления с остальной частью шаблона; он может выполнять произвольное обратное отслеживание без переполнения стека, но для этого может потребоваться чрезмерное количество времени.)