Регулярное выражение для соответствия любому количеству повторений, кроме k

#regex

Вопрос:

Я пытаюсь найти весь текст, который не соответствует следующему шаблону ^([^.]*.){3}[^.]*$ , т. Е. любой текст, разделенный 3 точками (.), например XXX.XXX.XXX.XXX соответствует, XX.XX или XX.XX.XX.XX.XX. XX не соответствует.

Любой символ, кроме точки, может быть использован вместо X, т. Е. Я хочу, по сути, подсчитать количество периодов в строке и отфильтровать по количеству <> 3 (приведенное выше выражение делает обратное, т. Е. Соответствует, когда количество == 3)

Как вы скажете, соответствует 1,2 или 4 раза?

Комментарии:

1. Можете ли вы привести еще пару примеров строк, которые должны / не должны совпадать, пожалуйста. Каким персонажам разрешено ходить туда, куда вы должны X ?

2. X может быть чем угодно, кроме .

3. Может ли строка быть XX.X.XX или известно, что число X одинаково для каждой группы; т. Е. Неизвестно только число для каждой группы? Может ли строка быть AB.CD.EF или должны ли все символы в строке, кроме точек (крестиков), быть одним и тем же символом? Если последнее, известен ли этот персонаж?

4. Количество X в группе варьируется (любое число) и может быть любым символом (кроме самого разделителя). В основном у меня есть данные с разделителями, и я пытаюсь найти искаженные строки — я использую Google OpenRefine, поэтому использую регулярные выражения, а не просто подсчитываю разделители. Так что думайте об этом как о данных CSV (но с . как разделитель) с некоторыми записями, имеющими «неправильное» количество полей.

Ответ №1:

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

Общая идея:

 (?!^not_this_pattern$)^[sS]*$
 

[sS] захватывайте все, что угодно, включая новую строку (в отличие от . )

И для этого примера:

 (?!^([^.]*.){3}[^.]*$)^[sS]*$
 

ДЕМОНСТРАЦИЯ

Или альтернативно используйте оператор условия | для повторения шаблона (2 или менее) или (4 или более):

 ^((?:[^.]*.[^.]*){,2}|(?:[^.]*.[^.]*){4,})$
 

ДЕМОНСТРАЦИЯ

Ответ №2:

Во-первых, я собираюсь упростить ваш вопрос до основной части: как сопоставить любое количество повторений, кроме k . С этой целью я упрощу выражение до x . В конце концов, это должно работать с любым выражением, так что с таким же успехом можно начать с простого.

Регулярное выражение предоставляет нам две полезные конструкции:

  1. Конструкция «n или более» {n,}
    • Это указывает, что вы хотите, чтобы это выражение повторялось n или более раз.
  2. Конструкция «диапазон» {n,m}
    • Это указывает , что вы хотите, чтобы это выражение повторялось любое количество раз между n и m включительно.

Мы можем собрать их вместе, используя регулярное выражение ИЛИ обозначение ( | ), чтобы сопоставить «от 1 до k - 1 2 раз» ( {1,k-1} ) и « k 1 или более раз» ( {k 1,} ) отдельно. Мы используем k - 1 и k 1 в качестве границ, потому что обе эти функции являются включающими, и мы хотим исключить k . Если бы мы хотели k быть, скажем, 3, мы бы получили следующее выражение:

 ^(x{1,2}|x{4,})$
 

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

 ^(x)((?1){0,1}|(?1){3,})$
 

Обратите внимание, что я использовал от 0 до 1 и 3 в качестве своих кванторов, потому что мы уже сопоставляли выражение один раз в начале нашего шаблона. Одно предостережение здесь заключается в том, что не все варианты регулярных выражений поддерживают этот синтаксис. PCRE (и PCRE2) поддерживает его, но Python, Golang, Java и ECMAScript этого не делают.

Теперь все, что нам осталось, — это подключить ваш шаблон. Очень просто, мы можем просто поместить его туда, где x есть в наших предыдущих шаблонах:

Используя первый метод, если вы не используете PCRE или у вас есть короткое выражение:

 ^(([^.]*.){1,2}|([^.]*.){4,})[^.]*$
 

И используя второй метод, если вы используете PCRE и у вас длинное выражение:

 ^([^.]*.)((?1){0,1}|(?1){3,})[^.]*$