Извлечение пар ключ-значение из многострочного текста в java

Рассмотрим следующую многострочную строку:

This is multiline text that needs to be correctly parsed into key-value pairs, excluding all other information.

 Section One:
    First key = Value One
    Second key = Value Two

 Section Two:   
    Third key = Value Three
    Fourth key = Value Four
    Fifth key = Value Five

 Section Three:
    Sixth key = Value Six
    Seventh key = Value Seven
    Eighth key = Value Eight

Другими словами, текст состоит из «введения» (несколько фраз), за которыми следуют несколько строк, организованных в разделы, каждый из которых имеет «заголовок» (например, Section One) и несколько пар ключ-значение, разделенных =. .

Ключи могут содержать любой символ, кроме новой строки и =, а значения могут содержать любой символ, кроме новой строки.

Иногда в тексте могут появляться другие нерелевантные строки.

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

В идеале не требуется никакой другой предварительной или последующей обработки текста.

Чтение текста построчно и соответствующая обработка в этом случае невозможны.

Такие шаблоны, как (?:\r|\n)(\s*[^=\.]+)\s*=\s*(.+), близки, но они все еще включают в себя немного больше требований.

Любые идеи?


person PNS    schedule 12.02.2015    source источник
comment
Если интервал постоянный, также попробуйте (?m)(?<=^ {4}).+?(?= *= *(.*))   -  person Jonny 5    schedule 12.02.2015
comment
Интервал не постоянный, он не работает. Спасибо хоть. :-)   -  person PNS    schedule 12.02.2015
comment
Не могли бы вы подробнее рассказать о том, Чтение текста построчно и соответствующая обработка в данном случае невозможны.?   -  person Sabir Khan    schedule 29.03.2019


Ответы (1)


Ты почти там . Просто измените \s* на <space>*, потому что \s также соответствует символу новой строки.

(?:\r|\n) *([^\n=\.]+)(?<=\S) *= *(.+)

Если он содержит вкладки, измените space* выше на [ \t]*. (?<=\S) Положительный просмотр назад, который утверждает, что совпадению должен предшествовать символ, не являющийся пробелом.

ДЕМО

String s = "This is multiline text that needs to be correctly parsed into key-value pairs, excluding all other information.\n" + 
        "\n" + 
        " Section One:\n" + 
        "    First key = Value One\n" + 
        "    Second key = Value Two\n" + 
        "\n" + 
        " Section Two:   \n" + 
        "    Third key = Value Three\n" + 
        "    Fourth key = Value Four\n" + 
        "    Fifth key = Value Five\n" + 
        "\n" + 
        " Section Three:\n" + 
        "    Sixth key = Value Six\n" + 
        "    Seventh key = Value Seven\n" + 
        "    Eighth key = Value Eight";
Matcher m = Pattern.compile("(?:\\r|\\n)[\\t ]*([^\\n=\\.]+)(?<=\\S)[\\t ]*=[\\t ]*(.+)").matcher(s);
while(m.find())
{
    System.out.println("Key : "+m.group(1) + " => Value : " + m.group(2));
}

Вывод:

Key : First key => Value : Value One
Key : Second key => Value : Value Two
Key : Third key => Value : Value Three
Key : Fourth key => Value : Value Four
Key : Fifth key => Value : Value Five
Key : Sixth key => Value : Value Six
Key : Seventh key => Value : Value Seven
Key : Eighth key => Value : Value Eight
person Avinash Raj    schedule 12.02.2015
comment
Или мы можем использовать \s* для включения вкладок. - person PNS; 12.02.2015
comment
вот почему я сказал вам добавить [ \t]* - person Avinash Raj; 12.02.2015
comment
Конечно. Существует проблема с некоторыми заголовками разделов, за которыми следует вкладка - по какой-то причине регулярное выражение объединяет каждый такой заголовок с первым ключом в разделе. Первая версия проще и дает те же результаты, что и вторая. +1 уже и спасибо. - person PNS; 12.02.2015
comment
Действительно ли \s соответствует новой строке? Мое впечатление, что это не так. - person PNS; 12.02.2015
comment
Ты прав. Тогда (?:\r|\n) * можно заменить на \s*. - person PNS; 12.02.2015
comment
но не знаю, действительно ли существует разрыв строки или нет. - person Avinash Raj; 12.02.2015