#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
. В конце концов, это должно работать с любым выражением, так что с таким же успехом можно начать с простого.
Регулярное выражение предоставляет нам две полезные конструкции:
- Конструкция «n или более»
{n,}
- Это указывает, что вы хотите, чтобы это выражение повторялось
n
или более раз.
- Это указывает, что вы хотите, чтобы это выражение повторялось
- Конструкция «диапазон»
{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,})[^.]*$