Java 8 регулярное выражение: группа захвата в шаблоне не совпадает, но весь шаблон соответствует - PullRequest
2 голосов
/ 29 января 2020

Это мой первый вопрос. Приятно познакомиться со всеми.

Я создал следующий шаблон регулярных выражений в Java 8 (это просто упрощенный пример того, что я на самом деле имею в своем коде - для ясности):

(?<!a)([0-9])\,([0-9])(?!a)|(?<!b)([0-9]) ([0-9])(?!b)|(?<!c)([0-9])([0-9])(?!c)

, поэтому в общем случае он состоит из трех альтернатив: 1-й соответствует двум одиночным цифрам, разделенным запятой, например:

1,1
2,0
4,5

2-й соответствует двум однозначным цифрам, разделенным пробелом, например:

1 1
2 0
4 5

3-я соответствует двум одиночным цифрам в строке, например:

11
20
45

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

([0-9])[, ]?([0-9])

Каждая из совпавших цифр заключена в группу захвата, и теперь у меня есть вторая строка, чтобы «вызвать» эти захваченные числа как это:

(?<!n)($1 $2|$3 $4|$5 $6)(?!n)

Так что в конце мне нужно сопоставить текст, который будет иметь те же цифры, разделенные одним пробелом и не окруженные 'n'. Таким образом, если любой из приведенных выше примеров будет соответствовать шаблону из 1-й строки, шаблон 2-й строки должен соответствовать этим:

1 1
2 0
4 5
11 11
22 00
44 55 

И ни одному из них:

n1 1
2,0
45
asd asd asd

Проблема в следующем: он возвращает совпадение, даже если у меня нет этих захваченных цифр в тестируемом тексте, , но в нем есть пробел ... Так что здесь я не получаю совпадение, и это правильно:

aaaaaaaaa
bbbbbbbbb
aasdfasdf

но здесь я получаю совпадение по следующим вещам (наиболее очевидно, потому что есть пробел / пробелы):

abc abc
q w r t y
as df

Кто-нибудь знает, нормально ли это что, несмотря на тот факт, что символы в группах захвата не захвачены 1-й строкой, часть «группы без захвата» (таким образом, один пробел) будет сопоставлена, и поэтому весь шаблон возвращает совпадение, как если бы группа захвата могла быть совпадение нулевой длины во второй строке, если ничто не зафиксировано первой строкой? Заранее спасибо за любой комментарий по этому поводу.

1 Ответ

0 голосов
/ 28 февраля 2020

Ваше регулярное выражение соответствует пробелу, потому что результирующий шаблон для строки 1,1 равен (?<!n)(1 1| | )(?!n), и он может соответствовать пробелу, которому не предшествует и не следует пробел.

При замене обратная ссылка не соответствует ни одной строке в .replaceAll / .replaceFirst ей присваивается пустая строка (ей присваивается ноль при использовании .find() / .matches() ), и, таким образом, вы по-прежнему получаете пустые альтернативы в результирующем шаблоне.

Вы можете использовать эту функциональность И тот факт, что каждая альтернатива имеет ровно две группы захвата путем объединения обратных ссылок в строке шаблон замены, избавление от чередования в целом:

ПОИСК : (?<!a)([0-9]),([0-9])(?!a)|(?<!b)([0-9]) ([0-9])(?!b)|(?<!c)([0-9])([0-9])(?!c) REPLACE : (?<!n)($1 $2|$3 $4|$5 $6)(?!n)

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

См. Демонстрационный пример regex .

Обратите внимание, что , даже если количество групп отличается в зависимости от альтернативы , вы можете просто добавить «поддельные» пустые группы к каждому из них, и этот подход все еще будет работать.

...