Regex: Согласование путем исключения, без надежды - возможно ли это?
В некоторых вариантах регулярных выражений [отрицательные] утверждения нулевой ширины (look-ahead/look-behind) не поддерживаются.
Это делает чрезвычайно сложным (невозможным?) утверждение исключения. Например, "каждая строка, которая не имеет" foo "на ней", вот так:
^((?!foo).)*$
Можно ли добиться такого же результата без использования внешнего вида (сложность и проблемы производительности на данный момент отложены)?
Ответы
Ответ 1
ОБНОВЛЕНИЕ: Он не работает с двумя ff до оо, поскольку @Ciantic указал в комментариях.
^(f(o[^o]|[^o])|[^f])*$
ПРИМЕЧАНИЕ. Намного проще просто свести совпадение на стороне клиента вместо использования указанного выше регулярного выражения.
Регулярное выражение предполагает, что каждая строка заканчивается новой строкой char, если она не видна в регулярных выражениях С++ и grep.
Примеры программ в Perl, Python, С++ и grep
дают одинаковый вывод.
-
perl
#!/usr/bin/perl -wn
print if /^(f(o[^o]|[^o])|[^f])*$/;
-
python
#!/usr/bin/env python
import fileinput, re, sys
from itertools import ifilter
re_not_foo = re.compile(r"^(f(o[^o]|[^o])|[^f])*$")
for line in ifilter(re_not_foo.match, fileinput.input()):
sys.stdout.write(line)
-
С++
#include <iostream>
#include <string>
#include <boost/regex.hpp>
int main()
{
boost::regex re("^(f(o([^o]|$)|([^o]|$))|[^f])*$");
//NOTE: "|$"s are there due to `getline()` strips newline char
std::string line;
while (std::getline(std::cin, line))
if (boost::regex_match(line, re))
std::cout << line << std::endl;
}
-
grep
$ grep "^\(f\(o\([^o]\|$\)\|\([^o]\|$\)\)\|[^f]\)*$" in.txt
Пример файла:
foo
'foo'
abdfoode
abdfode
abdfde
abcde
f
fo
foo
fooo
ofooa
ofo
ofoo
Вывод:
abdfode
abdfde
abcde
f
fo
ofo
Ответ 2
Обычно вы можете искать foo и инвертировать результат соответствия регулярного выражения из кода клиента.
Для простого примера предположим, что вы хотите проверить, что строка содержит только определенные символы.
Вы можете написать так:
^[A-Za-z0-9.$-]*$
и принять результат true
как действительный, или вот так:
[^A-Za-z0-9.$-]
и принять результат false
как действительный.
Конечно, это не всегда вариант: иногда вам просто нужно поставить выражение в файл конфигурации или передать его в другую программу, например. Но стоит вспомнить.
Ваша конкретная проблема, например, выражение намного проще, если вы можете использовать такое отрицание.
Ответ 3
Я наткнулся на этот вопрос, ища свое собственное решение исключения регулярных выражений, где я пытаюсь исключить последовательность в моем регулярном выражении.
Моя первоначальная реакция на эту ситуацию: например, "каждая строка, которая не имеет" foo "на ней", просто заключалась в использовании опции -v инвертировать значение соответствия в grep.
grep -v foo
это возвращает все строки в файле, который не соответствует 'foo'
Это так просто, у меня есть сильное чувство, что я просто неправильно понял ваш вопрос....