[regexp] не вхождение слова.

danilov

Хочу поискать подстроку начинающуюся с 'a', заканчивающуюся на 'b' и не содержащую 'cdefg'.
Существует ли простой способ написать такой запрос?
Я делал это запросом a([^c]|c[^d]|cd[^e]|cde[^f]|cdef[^g])*b
Это как-то громоздко при большой длине слова.
Прочтение доков не помогло.
Если такого способа нет, есть ли средства, позволяющие составлять такие запросы (желательно такие же функциональные, как regexp)?

artimon

Самое простое, сначала найти строку a.*b, а потом проверить, что внутри нет сdefg

danilov

А как можно тем же запросом проверить?
Допустим, мне надо сделать автозамену в более 1000 мест.
upd. А мой-то запрос не работает, придётся ещё отдельно рассматривать вхождения cb, cdb итд, что делает его ещё более громоздким

artimon

Написать программу на sed или perl
И сформулируй менее абстрактную задачу.

Marusetta

(ошибся, не работает)

artimon

Я не знаю какие ты читаешь доки, но
$ perl -n -e ' /a.*b(?<!\A.*cdefg.*\G)/ and print $&, "\n"'  b
Variable length lookbehind not implemented in regex m/a.*b(?<!\A.*cdefg.*\G)/ at -e line 1.

Serega009

upd. А мой-то запрос не работает, придётся ещё отдельно рассматривать вхождения cb, cdb итд, что делает его ещё более громоздким
Не отловит и accdefgb.
А принципиально сделать в одно выражение? Я бы поступил как .
Можно использовать вариации, аля:
s#%#%1#g
s#cdefg#%2#g
Потом отлавливать подстроки так, например:
m#a(?:[^%]*|%1)*b#
Затем обратное преобразование:
s#%2#cdefg#g
s#%1#%#g

danilov

Менее абстрактная задача не решит проблему, так как именно хотелось узнать, умеет ли такое regexp, и если нет, то чем его можно заменить.
А конкретный запрос уже решён (преведённым способом) и не актуален. Просто казалось странным, что простого исключения там задать нельзя.
За sed спасибо, копаюсь.

Marusetta

т.к. я сижу под виндой, пользую софт от JGSoft, собственно, и доки их.
но там все равно ошибка была, да и \A я не пойми зачем впихнул, черт попутал
вот, относительно правильный вариант:
(?>a?!cdefg).)*b)
правда, если у тебя "cdefg" будет перекрываться с "b" (ну, в реальных примерах может не сработать
ща еще подумаем
upd. усе работает

danilov

> Не отловит и accdefgb
Это и имелось ввиду.
> А принципиально сделать в одно выражение? Я бы поступил как .
Нет, но принципиально, чтобы затраченное время не зависело от кол-ва запросов.
Возможно, то, что ты предлагаешь и не зависит, но я не помнимаю, что там написано . Это на чём вообще?
И что значит потом отлавливать подстроки? Где их отлавливать?

Serega009

> Это и имелось ввиду.
Я подумал, ты про такие подстроки: acb (после c должно быть что-то кроме d, а затем уже может быть b).
Я предложил такое: заменить все проценты на %1, а cdefg на %2.
Потом с полученной строкой сделать все манипуляции, а затем преобразовать %2 на cdefg, а %1 на %.

doublemother

В заглядываниях запрещено использовать строки переменной длины.

klyv

как, ты тоже читать умеешь?
не "в заглядываниях", а "в заглядываниях назад" ;)

doublemother

Прикинь, да?
В заглядываниях вперед, насколько я помню, тоже.

klyv

в этом не прав. вперёд - всё можно.
назад и переменной длины - сложно реализовывать, большой оверхед.

danilov

Нда, так можно...
но в общем случае, если b == cdefg, то не сработает.

Marusetta

майндфак
таки фэйлит
при регексе q?!ation).)*o на слове quantization должен быть матч, а его нет
таки я не знаю как это сделать в один проход. Все равно как-то надо пометить что "дальше вот этого места - не искать".
разве что явно указать альтернативу: q(?:(?!ation).)*(?:o|atio), но это уже никак не подходит к параметризованному поиску, да

klyv

а если q?!ation).)*.{4}|.{0,4})o?

Marusetta

кстати с примером "a" = лол, "b" = лол, "cdefg" = ололо, и текстом "ололололо" не работает.

kruzer25

Лол.

RusRaul

a(^cfdg)*.?b$

danilov

Это, вроде как, a, затем несколько раз (или 0) (символ, не совпадающей с c)fdg, а затем ещё что-то не пустое, затем b
А это не то

Barbie29

Хочу поискать подстроку начинающуюся с 'a', заканчивающуюся на 'b' и не содержащую 'cdefg'

попробуй это: print "$1 $2 $3 \n" if $_=~/(?<!a.*?cdefgh.*?!\b)/
написал сходу... по идее оно должно искать подстроку перед которой нет 'a' и после которой нет 'b'...

doublemother

Во-первых, что ты подразумеваешь под $1 и $3? У тебя здесь будет захватываться только одна подстрока. А во-вторых, ты пытаешься решить ровно противоположную задачу.
P.s. Да, а упомянутый тобою \b - это символ границы слова, а не буква b.

Barbie29

для инвертирования так: print "$1 $2 $3 \n" if $_=!/(?<!a.*?cdefgh.*?!\b)/
для множественных совпадений вот так: print "$1 $2 $3 \n" while $_=!/(?<!a.*?cdefgh.*?!\b)/gs
не проверял.. почему $1 $2 $3 - сила привычки, иногда чтото полезное видишь не там где хотелось бы.

Barbie29

* (?= шаблон) - после этой точки есть фрагмент текста, который соответствует указанному регулярному выражению
* (?! шаблон) - после этой точки нет текста, который бы соответствовал указанному регулярному выражению,
* (?<= шаблон) - перед этой точкой есть фрагмент текста, соответствующий указанному регулярному выражению,
* (?<! шаблон) - перед этой точкой нет фрагмента текста, соответствующего указанному регулярному выражению.
* (?#текст) - комментарий. Текст комментария игнорируется.
* (?:шаблон) или (?модификаторы:шаблон) - группирует элементы шаблона. В отличие от обычных круглых скобок, не создает нумерованной переменной. Например, модификатор i не будет делать различия между строчными и заглавными буквами, однако область действия этого модификатора будет ограничена только указанным шаблоном.
* (?=шаблон) - "заглядывание вперед". Требует, чтобы после текущей точки находился текст, соответствующий данному шаблону. Такая, конструкция обрабатывается как условие или мнимый символ, поскольку не включается В результат поиска. Например, поиск с помощью команды /w+(?=\s+)/ найдет слово, за которым следуют один или несколько "пробельных символов", однако сами они в результат не войдут.
* (?!шаблон) - случай, противоположный предыдущему. После текущей точки не должно быть текста, соотносимого с заданным шаблоном. Так, если шаблон w+(?=\s) - это слово, за которым следует "пробельный символ", то шаблон w+(?!\s) - это слово, за которым мет "пробельного символа".
* (?<=шаблон) - заглядывание назад. Требует, чтобы перед текущей точкой находился соответствующий текст. Так, шаблон (?<=\s)w+ интерпретируется как слово, перед которым имеется пробельный символ (в отличие от заглядывания вперед, заглядывание назад может работать только с фиксированным числом проверяемых символов).
* (?<!шаблон) - отрицание предыдущего условия. Перед текущей точкой не должно быть текста, соотносимого с заданным шаблоном. Соответственно, от команды /(?<!\s)w+/ требуется найти слово, перед которым нет пробельного символа.
* (?{код}) - условие (мнимый символ которое всегда выполняется. Сводится к выполнению команд perl в фигурных скобках. Вы можете использовать эту конструкцию, только если в начале сценария указана команда use re 'eval'. При последовательном соотнесении текста и шаблона, когда perl доходит до такой конструкции, выполняется указанный код. Если полного соответствия для оставшихся элементов найти не удалось, то при возврате левее данной точки шаблона вычисления, проделанные с локальными переменными, откатываются назад. (Условие является экспериментальным. В документации, прилагаемой в perl, можно найти довольно детальное рассмотрение (с примерами) работы этого условия и возможных трудностей в случае его применения.)
* (?>шаблон) - "независимый" или "автономный" шаблон. Используется для оптимизации процесса поиска, поскольку запрещает "поиск с возвратом". Такая конструкция соответствует подстроке, на которую налагается заданный шаблон, если его закрепить в текущей точке без учета последующих элементов шаблона. Например, шаблон (?>а*)аb в отличие от a*ab не может соответствовать никакой строке. Если поставить в любом месте шаблон а*, он съест все буквы а, не оставив ни одной шаблону ab. (Для шаблона а*аb "аппетит" квантификатор * будет ограничен за счет работы поиска с возвратами: после того как на первом этапе не удастся найти соответствие между шаблоном и текстом, perl сделает шаг назад и уменьшит количество букв а, захватываемых конструкцией а*.)
* (?(условие)шаблон-да|шаблон-нет) или (?(условие)шаблон-да) - условный оператор, который подставляет тот или иной шаблон в зависимости от выполнения заданного условия. Более подробно описан в документации perl.
* (?модификаторы) - задает модификаторы, которые локальным образом меняют работу процедуры поиска. В отличие от глобальных модификаторов, имеют силу только для текущего блока, то есть для ближайшей группы круглых скобок, охватывающих конструкцию, Например, шаблон ?i)text) соответcтвует слову "text" без учета регистра.

doublemother

Замечательная шпаргалка, если бы ты ей еще пользовался. Твой регэксп опять - унылая хуйня.
Во-первых отрицание тогда уж надо было писать как:
print "$1 $2 $3 \n" if $_!~ /(?<!a.*?cdefgh.*?!\b)/ 

Во-вторых, под это твоё отрицание попадёт что угодно, например:
print "Lalala\n" if "Vilfred loh" !~ /(?<!a.*?cdefgh.*?!\b)/;

Просто замечательно срабатывает, хотя искомых букв a и b там нет. Сходи регэкспы поучи лучше)

Barbie29

а почему ты такой злой? :crazy: это первое
а второе яж написал сразу что не проверял регексп... копать надо в ту сторону.

doublemother

Просто "этот пацак всё время говорит на языках, продолжения которых не знает". (c)

Barbie29

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

doublemother

Для конкретного данного случая ("a ... b" с отсутствием cdefg в промежутке) это проще всего сделать тупым проходом по строке. Иначе - проще в два регэкспа.
Оставить комментарий
Имя или ник:
Комментарий: