Регулярное выражение Java для поиска нескольких строк определенной длины - PullRequest
5 голосов
/ 22 ноября 2010

Я пытаюсь использовать регулярные выражения Java для соответствия шаблону, который занимает несколько строк. У шаблона есть одна строка, которая начинается с «A», за которой следуют ровно 50 символов, а затем одна или несколько строк, начинающихся с «B», за которыми следуют ровно 50 символов:

A...    //  exactly 50 chars after the A
B...
B...

Регулярные выражения Java, похоже, не поддерживают это.

Вот регулярное выражение, которое работает для одной строки A и одной строки B:

A.{50}[\\n[\\n\\r]]B.{50}[\\n[\\n\\r]]

Вот то же регулярное выражение, измененное для поиска одной или нескольких строк B:

A.{50}[\\n[\\n\\r]][B.{50}[\\n[\\n\\r]]]+

Однако это регулярное выражение находит только первый символ B в первой строке B.

Я использую [\\n[\\r\\n]] для работы с переводами DOS и UNIX. Включение режима MULTILINE не влияет на результаты.

Проблема, похоже, заключается в том, что я использую скобки с '+', чтобы превратить регулярное выражение для строки B в класс символов, который может захватывать несколько строк.

Есть ли что-то в регулярных выражениях Java, которые не допускают '.' символ или фигурные скобки для указания точной длины строки?

Ответы [ 6 ]

0 голосов
/ 22 ноября 2010

Это также должно работать:

Pattern regex = Pattern.compile("^A.{50}$\\s+(?:^B.{50}$\\s*)+(?:^|\\z)", Pattern.MULTILINE);

Причина этого заключается в том, что ^ соответствует началу строки, $ соответствует концу строки, перед (необязательно)символ новой строки, а \s соответствует пробелу, который включает \r и \n.Так как мы используем его между $ и ^, он может соответствовать только символам новой строки, но не другим пробелам.

(?:^|\\z) используется, чтобы убедиться, что мы случайно не сопоставляем ни одно из ведущихпробелы в строке, следующей за последним повторением строки B.Если строки никогда не начинаются с пробела, вы можете опустить этот бит.

0 голосов
/ 22 ноября 2010

Правильный способ сопоставления последовательности разрыва строки:

"(?:(?>\\u000D\\u000A)|[\\u000A\\u000B\\u000C\\u000D\\u0085\\u2028\\u2029)"

Это, конечно, в слабой нотации Java-строк, как вы можете перейти к Pattern.compile. Более разумные языки позволяют вам обойтись просто этим:

(?:(?>\x0D\x0A)|\v)

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

Удачи: она вам понадобится. ☹

0 голосов
/ 22 ноября 2010

Точка и фигурные скобки работают нормально;остальная часть вашего регулярного выражения неправильна.Проверьте это:

Pattern p = Pattern.compile("^A.{50}(?:(?:\r\n|[\r\n])B.{50})+$");

(?:\r\n|[\r\n]) соответствует последовательности CRLF, только CR или только LF.(Я мог бы использовать две обратные косые черты, как и вы, но это тоже работает).

Если вы используете регулярное выражение для извлечения совпадений из более крупного текста, вам нужно скомпилировать его в режиме MULTILINEпоэтому якоря ^ и $ могут совпадать на границах строк.Если предполагается, что он соответствует целой строке, оставьте ее в режиме по умолчанию, чтобы они соответствовали только началу и концу строки.

0 голосов
/ 22 ноября 2010

Это должно работать:

String input = "A1234567890\nA12345678\nA12345678\nB12345678\nA123456\nA1234567\nZA12345678\nB12345678\nA12345678\nB12345678\nB12345678\nB12345678\nB1234567\nA12345678\nB12345678";

String regex = "^A.{8}$((\\r|\\r\\n|\\n)^B.{8}$)+(\\r|\\r\\n|\\n|\\z)";

Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
Matcher matcher = pattern.matcher(input);

while (matcher.find()) {
System.out.println("matches from " + matcher.start() + " to " + matcher.end());
}

Примечание:

  1. использование ^, $ и MULTILINE, чтобы избежать совпадения со строкой, начинающейся с "ZA".
  2. использование (\\r|\\r\\n|\\n) для сопоставления Unix, Windows и старых строк Mac-OS.
  3. использование (\\r|\\r\\n|\\n|\\z) для сопоставления последней строки B без конца строки

Opsss, я использовал 8 вместо 50 для повышения читабельности.

0 голосов
/ 22 ноября 2010

В следующем регулярном выражении:

(A[^\r\n]{50}(\r\n|\n))(B[^\r\n]{50}(\r\n|\n))+

Я использовал [^\r\n], чтобы сопоставить любой символ, который не \r или \n.Например, вы можете заменить его на [\d], если у вас есть цифры.

См. http://www.myregextester.com/?r=b7c3ca56

В этом примере регулярное выражение соответствует всем, кроме последней строки.

0 голосов
/ 22 ноября 2010

Для работы с новой строкой в ​​стиле Unix и Dos вы можете использовать:

\\r?\\n

Также ваш способ группировки одной или нескольких B строк неверен, вы используете [] для группировки, вам следуетвместо этого используйте (?: ).

Попробуйте это регулярное выражение:

A.{50}\\r?\\n(?:B.{50}(?:\\r?\\n)?)+

Проверенное здесь регулярное выражение

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...