Регулярное выражение до, но не включая

81

Каков синтаксис для регулярного выражения поиска до, но не включая? Вроде как:

Haystack:
The quick red fox jumped over the lazy brown dog

Expression:
.*?quick -> and then everything until it hits the letter "z" but do not include z
Лапша Смерти
источник

Ответы:

162

Явный способ сказать «искать до, Xно не включая X»:

(?:(?!X).)*

где Xможет быть любое регулярное выражение.

Однако в вашем случае это может быть излишним - здесь проще всего

[^z]*

Это будет соответствовать чему угодно, кроме zи, следовательно, остановится непосредственно перед следующим z.

Так .*?quick[^z]*будет совпадать The quick fox jumps over the la.

Однако, как только у вас есть более одной простой буквы, на которую нужно обратить внимание, (?:(?!X).)*в игру вступает, например,

(?:(?!lazy).)*- совпадать с чем угодно до начала слова lazy.

Это использует утверждение опережающего просмотра , а точнее отрицательного просмотра вперед.

.*?quick(?:(?!lazy).)*будет соответствовать The quick fox jumps over the.

Пояснение:

(?:        # Match the following but do not capture it:
 (?!lazy)  # (first assert that it's not possible to match "lazy" here
 .         # then match any character
)*         # end of group, zero or more repetitions.

Кроме того, при поиске ключевых слов вы можете захотеть окружить их якорями границы слова: \bfox\bбудет соответствовать только полному слову, foxно не лису внутри foxy.

Запись

Если сопоставляемый текст может также включать разрывы строк, вам нужно будет установить опцию «точка соответствует всем» вашего механизма регулярных выражений. Обычно вы можете добиться этого, добавив (?s)к регулярному выражению, но это не работает во всех механизмах регулярных выражений (особенно в JavaScript).

Альтернативное решение:

Во многих случаях вы также можете использовать более простое и удобочитаемое решение, в котором используется ленивый квантификатор. Добавляя ?к *квантификатору, он попытается сопоставить как можно меньше символов с текущей позиции:

.*?(?=(?:X)|$)

будет соответствовать любому количеству символов, останавливаясь непосредственно перед X(что может быть любым регулярным выражением) или концом строки (если Xне совпадает). Вам также может потребоваться установить параметр «точка соответствует всем», чтобы это работало. (Примечание: я добавил группу без захвата X, чтобы надежно изолировать ее от чередования)

Тим Пицкер
источник
+1 Действительно хороший ответ, к сожалению, не работает grep, но этот ответ работает.
Alexandre Lavoie
@AlexandreLavoie: Интересно. Почему должен работать другой, а не этот? Оба используют утверждения с опережением. Возможно, это просто из-за(?:...) не захватывающей? С ним работает ((?!X).)*?
Тим Пицкер
1
На самом деле не знаю, я не эксперт по регулярным выражениям и не grep. Я использовал grepдля фильтрации запросов только для одной базы данных из преобразования bin mysql в sql. Вот зверь:grep -Po "(?s)use database_to_keep(.*?)(?=^use)" mysql-bin.000045.sql > filtered.sql
Александр Лавуа
Похоже на конфликт bash, поскольку, когда я нажимаю Upклавишу, последняя команда не та, которую я использовал:grep -Po "(?s)use database_to_keep(.*?)(?:(?!^use).)*" mysql-bin.000045.sql > filtered.sql
Александр Лавуа
1
Хорошее редактирование, @Tim, просто добавьте $альтернативу: замените .*?(?=X)на.*?(?=X|$)
Wiktor Stribiew
15

Синтаксис опережения регулярного выражения может помочь вам достичь вашей цели. Таким образом, регулярное выражение для вашего примера

.*?quick.*?(?=z)

И важно заметить .*?ленивое сопоставление перед (?=z)просмотром вперед: выражение соответствует подстроке до первого появления zбуквы.

Вот пример кода C #:

const string text = "The quick red fox jumped over the lazy brown dogz";

string lazy = new Regex(".*?quick.*?(?=z)").Match(text).Value;
Console.WriteLine(lazy); // The quick red fox jumped over the la

string greedy = new Regex(".*?quick.*(?=z)").Match(text).Value;
Console.WriteLine(greedy); // The quick red fox jumped over the lazy brown dog
Игорь Кустов
источник
0

Попробуй это

(.*?quick.*?)z
Максимум
источник
3
Это включает в себя букву «z» в совпадении, а именно этого спрашивающий хочет избежать. Возможно, регулярное выражение должно быть термином в '|' альтернатива, и это альтернативное регулярное выражение используется для выполнения нескольких совпадений. Если «z» - это начало строки, которой может соответствовать другой термин в альтернативе, то это совпадение будет аннулировано, поскольку «z» уже используется текущим совпадением.
Щепан Голышевский