Инвертировать regexp
выбирает значения, не попадающие в этотegrep -v "regex" "file", зачем париться.
/^(?!aaaa:21[012][01235]).{9}$/
для твоего примера можно так
Это нужно не для grep-а, это нужно для построения фильтра, которому надо скармливать regexp
Другой вопрос, поддерживает ли моя железка такие конструкции, это буду выяснять экспериментом.
Но в любом случае полезно знать, и, может быть, пригодиться когда буду программировать.
Zero-width negative look-ahead assertion. The enclosed pattern must
not match for the assertion to succeed. As with the positive variant,
match text is not consumed.
This pattern can be very tricky indeed to use correctly, and reaching for
it often indicates we need to rethink the design of our search pattern.
Firstly, because the assertion is zero width, we do not absorb any match
text even if it is satisfied, so we must take that into account in the
pattern immediately following. For example, this text attempts to make
sure the last three characters of a string are not “abc”. But it doesn’t
work:
$text=~/(?!abc)$/; # ERROR: always succeeds, even if $text ends
in 'abc'
This assertion will succeed at the very end of the match text, because at
the end there are no characters left, and this does satisfy the condition.
It will still satisfy the condition even if the last three characters really
were “abc”. To have this assertion work as intended, we need to provide
a positive-width pattern for the text that isn’t “abc” to match:
$text=~/(?!abc)...$/; # OK - note the '...'
The trailing dots change the meaning of this pattern from “check the
end is not ‘abc’’’ to “look for three characters at the end which are not
‘abc’.” While these parse the same to a human, the literal-minded
regular expression engine needs the extra clarification.
Secondly, alternatives do not work as might be expected inside this
assertion. For instance, we cannot say “neither ‘a’ nor ‘b’” with
$text=~/^(?!a|b)/;
# ERROR: matches any character
This actually says “not a” or “not b”. Since “a” is not “b”, and “b” is not “a”,
anything at all will satisfy one of these conditions and the assertion will
always succeed.
Like its positive counterpart, this pattern is zero width, so it does
not affect Perl’s special regular expression variables, backreferences,
or number variables.
это у тебя где такой регексп работает инвертированием вышенаписанного?
--- тут была написана глупость, удалено ---
есть подозрение, что .{9} задаёт жесткую длину в 9 символов.
>везде, где поддерживаются lookaround'ы
в js,grep,perl - хоть в одном из них они поддерживаются?
а то я не знаю что это такое.
признаю, я написал чушь, но как бы слово "фильтр" наводит на мысль, что на вход подаются форматные данные, и возможно, автору этого решения будет достаточно
есть подозрение что в общем случае это алгоритмически неразрешимо, но для конечных языков всё точно не так печально. =)
на самом деле разрешимо. регулярные выражения эквивалентны конечным автоматам, а построить отрицание конечного автомата очень просто, надо поменять терминальные и нетерминальные вершины местами.
ога
/(?!^aaaa:21[012][01235]$).{9}/
ну и, теперь попробуй туда подставить "Hello", стало совсем чуть-чуть получше, но все равно неправильно.
да, ты прав. все строки, короче девяти символов заваливают тест
что-нибудь такое?
ну построй по регулярному выражению конечный автомат, преобразуй его, и обратно переведи в регулярное выражение
perl:
if ($s !~ /^aaaa:21[012][01235]$/) { ... }
php:
if (!preg_match("/^aaaa:21[012][01235]$/", $s) { ... }
grep уже написали выше
и т.д.
И работать это будет намного быстрее, чем тот же look-around.
в этом случае, да. еще хотелось бы усилить его, чтобы не опираться на знание о начале и конце строки
а ты не можешь себе представить ситуацию, когда регексп передаётся в уже готовый метод, и даже если известны его исходники ты поимеешь кучу геммороя при обновлении.
Могу. Но, согласись, код if (x == 0) всё-таки обычно лучше, чем if (!(x>0) && !(x<0. Регэкспы обычно занимаются проверкой на соответствие шаблону, с этим они справляются лучше, чем с проверкой на несоответствие. Поэтому лучше стараться использовать их по назначению.
Если конкретней, то задача состоит в правильной реакции на bgp community, принимаемых от клиентов. У меня есть regexp по которому я выбираю community, на которые описана реакция и которые клиенты имеют право ставить, это задается изначальным regexp-ом, где заместо aaaa ставится номер моей автономной системы. Все остальные community из анонсов мне надо удалить, поэтому и пытаюсь построить некоторый инвертированный regexp.
Именно поэтому мне не подходят решения на основе grep, perl, php — мне не надо писать программу, мне надо составить regexp и впихнуть его в конфиг Juniper-а. И именно поэтому я не знаю как это правильно назвать: pcre или стандартный regexp. Конкретно, я хочу получить результат в терминах regexp-а для JunOS 9.1 И именно поэтому мне надо очень четко понять все то, что будет происходить, потому что не хочется в случае ошибки оставлять кучу народа без интернета.
Хотя, периодически я пишу разные вещи для разнообразных обработок, в том числе и на перле, поэтому отдельное спасибо за новые для меня данные про способы построения регулярных выражений. Да и кругозор просто надо расширять.
В итоге, спасибо за советы и за новые для меня знания, отдельное спасибо, что правильно восприняли мой изначальный вопрос. Но, похоже, сейчас буду придумывать какие-нить другие обходные моменты.
Хотя, может кто знает, как большие дядьки типа Level3 или ReTN решают данные проблемы?
Вряд ли на жуниперах такого нет, это было бы странно.
Оставить комментарий
Sharp
Есть regexp, который позволяет выбирать нужные значения. Для конкретики, это "^aaaa:21[012][01235]$"Как бы проще построить regexp, который выбирает значения, не попадающие в этот? Что-то у меня не получается просто взять и инвертировать его, и в голову приходят только идеи вида раскрыть этот regexp и выписать все варианты с префиксом инвертирования.