Regex для разделения многострочной строки

Рассмотрим многострочную строку, состоящую из N lines, например:

Line 1 text
Line 2 text
Line 3 text
...
Line n-1 text
Line n text
anchor=value
Line n+2 text
Line n+3 text
Line n+4 text
...
Line N text

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

Мне нужно регулярное выражение, которое разбивает указанную выше строку на 3 группы:

  1. Строка 1 до строки n (включительно)
  2. Линия привязки (точка раздела)
  3. Линия n+2 до линии N (включительно)

Самое близкое, что я получил к решению, это

(?s)^(?:(?!anchor\s*=\s*).)+?\r|\nanchor\s*=\s*([^\r\n]+)(?:\r|\n)(.*)

но приведенное выше регулярное выражение включает весь текст в первую соответствующую группу и заполняет оставшиеся 2 группы, как и ожидалось.

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

Любые идеи?


person PNS    schedule 02.03.2015    source источник


Ответы (3)


А как насчет этого регулярного выражения?

(?s)^(.*?)(anchor\s*\=\s*[^\r\n]+)(.*?)

Или, чтобы соответствовать концу строки,

(?s)^(.*?)(anchor\s*\=\s*[^\r\n]+)(.*?)$?

person Wiktor Stribiżew    schedule 02.03.2015
comment
Первый работает, если нежадный оператор в последней группе становится жадным. Секунды работают как есть. Спасибо! - person PNS; 03.03.2015
comment
@PNS, пожалуйста. Я знал, что шаблону (.*?) может потребоваться некоторая граница, поэтому я добавил второй вариант. - person Wiktor Stribiżew; 03.03.2015
comment
Да, они, кажется, в порядке. Спасибо. - person PNS; 03.03.2015

Если вам нужна скорость, огромные строки и регулярное выражение не подходят. Вы должны иметь всю строку в памяти, чтобы иметь возможность использовать регулярное выражение для ее токенизации. Вместо этого я рекомендую использовать Reader/InputStreams.

person RudolphEst    schedule 02.03.2015
comment
Конечно, но в этом случае вывод исходит из библиотеки, которая допускает настройку только с помощью регулярного выражения. - person PNS; 03.03.2015
comment
Теперь я еще больше запутался. Если вывод исходит из библиотеки, зачем вы делаете разбиение? Вы имеете в виду, что строка возвращается библиотекой? - person RudolphEst; 03.03.2015
comment
Он обрабатывается библиотекой, позволяющей внедрять регулярные выражения. - person PNS; 03.03.2015
comment
Библиотека @PNS, которая позволяет настраивать только с помощью регулярного выражения, эту информацию следует поместить в ваш вопрос. Также опишите, как именно это регулярное выражение будет применяться вашей библиотекой: будет ли это аргументом для split или, может быть, для find()? - person Pshemo; 03.03.2015
comment
Нет разделения, он применяется к блокам текста, как в примере, поэтому мы, вероятно, ищем совпадения(). - person PNS; 03.03.2015

Ну, можно было бы сначала достать якорь, а потом расколоться по нему:

String anchor = str.replaceAll("(?ms).*?(anchor\\s*=.*?)$.*", "$1");
String lineParts = str.split("\\Q" + anchor + "\\E");

Флаг "m" заставляет ^ и $ совпадать с началом/концом строк.

person Bohemian♦    schedule 02.03.2015
comment
Спасибо, но здесь нужно одно регулярное выражение, которое делает все это, потому что код не позволяет ничего другого. +1 в любом случае. :-) - person PNS; 03.03.2015