Шаблон Java вызывает переполнение стека

Я использую регулярное выражение для извлечения пар значений ключа -из произвольно длинных входных строк и столкнулся со случаем, когда длинная строка с повторяющимися шаблонами вызывает переполнение стека.

Код разбора KV -выглядит примерно так:

public static void parse(String input)
{
    String KV_REGEX = "((?:\"[^\"^ ]*\"|[^=,^ ])*) *= *((?:\"[^\"]*\"|[^=,^\\)^ ])*)";
    Pattern KV_PATTERN = Pattern.compile(KV_REGEX);

    Matcher matcher = KV_PATTERN.matcher(input);

    System.out.println("\nMatcher groups discovered:");

    while (matcher.find())
    {
        System.out.println(matcher.group(1) + ", " + matcher.group(2));
    }
}

Некоторые фиктивные примеры вывода:

    String input1 = "2012-08-09 09:10:25,521 INFO com.a.package.SomeClass - Everything working fine {name=CentOS, family=Linux, category=OS, version=2.6.x}";
    String input2 = "2012-08-09 blah blah 09:12:38,462 Log for the main thread, PID=5872, version=\"7.1.8.x\", build=1234567, other=done";

Вызов parse(input1)дает:

{name, CentOS
family, Linux
category, OS
version, 2.6.x}

Вызов parse(input2)дает:

PID, 5872
version, "7.1.8.x"
build, 1234567
other, done

Это нормально (даже с небольшой обработкой строк, необходимой для первого случая ). Однако при попытке проанализировать очень длинную (строку пути к классам длиной более 1000 символов )происходит вышеупомянутое переполнение класса со следующим исключением (start):

Exception in thread "main" java.lang.StackOverflowError
    at java.util.regex.Pattern$BitClass.isSatisfiedBy(Pattern.java:2927)
    at java.util.regex.Pattern$8.isSatisfiedBy(Pattern.java:4783)
    at java.util.regex.Pattern$8.isSatisfiedBy(Pattern.java:4783)
    at java.util.regex.Pattern$8.isSatisfiedBy(Pattern.java:4783)
    at java.util.regex.Pattern$8.isSatisfiedBy(Pattern.java:4783)
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3345)
   ...

Строка слишком длинная, чтобы поместить ее здесь, но она имеет следующую, легко воспроизводимую и повторяющуюся структуру:

java.class.path=/opt/files/any:/opt/files/any:/opt/files/any:/opt/files/any

Любой, кто хочет воспроизвести проблему, просто должен добавить :/opt/files/anyнесколько десятков раз к приведенной выше строке. После создания строки с примерно 90 копиями «:/opt/files/any», присутствующими в строке пути к классам, происходит переполнение стека.

Есть ли общий способ изменить приведенную выше строку KV_REGEX, чтобы проблема не возникала и были получены те же результаты?

Я явно указал общий выше, в отличие от хаков, которые (, например, )проверяют максимальную длину строки перед разбором.

Самое грубое исправление, которое я мог придумать, настоящий анти--паттерн, это

public void safeParse(String input)
{
    try
    {
        parse(input);
    }
    catch (StackOverflowError e) // Or even Throwable!
    {
        parse(input.substring(0, MAX_LENGTH));
    }
}

Как ни странно, это работает за несколько прогонов, которые я пробовал, но это не то, что достаточно со вкусом, чтобы рекомендовать.:-)

5
задан PNS 14 August 2012 в 22:25
поделиться