Ответ 1
Явным способом сказать "поиск до X
, но не включая X
":
(?:(?!X).)*
где X
может быть любым регулярным выражением.
В вашем случае, однако, это может быть излишним - здесь самый простой способ -
[^z]*
Это будет соответствовать чему-либо, кроме z
, и поэтому остановится прямо перед следующим z
.
Итак .*?quick[^z]*
будет соответствовать The quick fox jumps over the la
.
Однако, как только у вас будет более одного простого письма, которое нужно искать, (?:(?!X).)*
вступает в игру, например
(?:(?!lazy).)*
- сопоставить что-либо до начала слова lazy
.
Это использует утверждение lookahead, более конкретно - негативный взгляд.
.*?quick(?:(?!lazy).)*
будет соответствовать The quick fox jumps over the
.
Объяснение:
(?: # Match the following but do not capture it:
(?!lazy) # (first assert that it 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
не соответствует). Вам также может потребоваться установить параметр "dot matches all" для этого. (Примечание: я добавил группу без захвата вокруг X
, чтобы надежно изолировать ее от чередования)