sed: отрицание backreference в regex

На самом деле это единственный раздел про unix на этом форуме

Модераторы: /dev/random, Модераторы разделов

Аватара пользователя
SLEDopit
Модератор
Сообщения: 4823
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

sed: отрицание backreference в regex

Сообщение SLEDopit »

цель: удалить из текста строки без повторяющихся элементов перед и после указанного словом. слово может повторяться в одной строке несколько раз.

в интернетах написано, что это делается так:
/(.*)word(?!\1)/

но sed ругается или ничего не удаляет:

Код: Выделить всё

 $ echo {a,b,c}{word,d,e}{a:,b:,c:}|tr ':' '\n'|sed '/\(.\)word(?!\1)/d'
печать всех вариантов

 $ echo {a,b,c}{word,d,e}{a:,b:,c:}|tr ':' '\n'|sed -r '/(.)word(?!\1)/d'
sed: -e expression #1, char 15: Invalid preceding regular expression

 $ echo {a,b,c}{word,d,e}{a:,b:,c:}|tr ':' '\n'|sed -r '/(.)word(!\1)/d'
печать все вариантов


/(.)word\1/!d не подходит, т.к. в строке "word" может встречаться несколько раз.
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
Аватара пользователя
t.t
Бывший модератор
Сообщения: 7390
Статус: думающий о вечном
ОС: Debian, LMDE

Re: sed: отрицание backreference в regex

Сообщение t.t »

Конкретный пример строк можно?
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: sed: отрицание backreference в regex

Сообщение watashiwa_daredeska »

SLEDopit писал(а):
21.05.2010 12:13
в интернетах написано, что это делается так:
/(.*)word(?!\1)/
Это точно для sed написано? Больше похоже на perl.
Для sed придумалось:

Код: Выделить всё

sed -rn 'h;s/(.)word\1//g;ta;:a;s/word//;t;g;p'


Shell

$ cat | sed -rn 'h;s/(.)word\1//g;ta;:a;s/word//;t;g;p' <<EOF > xaworday > xaworday xawordcy > xawordcy > EOF xaworday
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: sed: отрицание backreference в regex

Сообщение watashiwa_daredeska »

P.S. Бага. В первой замене надо не удалять, а заменять на символ, которого нет в word, например, \n:

Shell

$ word=xxxx; cat | sed -rn 'h;s/(.)'"$word"'\1/\n/g;ta;:a;s/'"$word"'//;t;g;p' <<EOF xa${word}ay xa${word}ay xa${word}cy xa${word}cy xxx${word}xxx EOF xaxxxxay
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: sed: отрицание backreference в regex

Сообщение watashiwa_daredeska »

Хотя, тоже не идеал, есть случаи, когда это работает не так, как изначальный перловый regexp.
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4823
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: sed: отрицание backreference в regex

Сообщение SLEDopit »

t.t писал(а):
21.05.2010 12:27
Конкретный пример строк можно?

Код: Выделить всё

12_file_12_file_12
 12_file_12_file_23
 12_file_12_file_34
 12_file_23_file_12
 12_file_23_file_23
 12_file_23_file_34
 12_file_34_file_12
 12_file_34_file_23
 12_file_34_file_34
 23_file_12_file_12
 23_file_12_file_23
 23_file_12_file_34
 23_file_23_file_12
 23_file_23_file_23
 23_file_23_file_34
 23_file_34_file_12
 23_file_34_file_23
 23_file_34_file_34
 34_file_12_file_12
 34_file_12_file_23
 34_file_12_file_34
 34_file_23_file_12
 34_file_23_file_23
 34_file_23_file_34
 34_file_34_file_12
 34_file_34_file_23
 34_file_34_file_34
необходимо выделить строки, где до и после _file_ стоят одинаковые числа, т.е. из данных строк будет выделена только одна: 12_file_23_file_34
watashiwa_darede... писал(а):
21.05.2010 12:45
Хотя, тоже не идеал, есть случаи, когда это работает не так, как изначальный перловый regexp.
хм, но все равно спасибо. пока вроде на исключения не наткнулся.
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: sed: отрицание backreference в regex

Сообщение watashiwa_daredeska »

SLEDopit писал(а):
21.05.2010 13:04
где до и после _file_ стоят одинаковые числа
цифры?

SLEDopit писал(а):
21.05.2010 13:04
ока вроде на исключения не наткнулся.
Исключения могут быть в том случае, если имеются перекрытия. Например, 1_file_2_file_3 — «2» здесь является разделителем и для первого, и для второго _file_, поэтому 1_file_1_file_1 не будет «выделено». Ещё хуже, когда word и разделители имеют пересекающийся алфавит и могут перекрываться ещё суровее: word="abcabc"; line="aabcabcabcc" — эта строка вполне удовлетворяет требованиям (т.е. не удовлетворяет исходному regexp'у для удаления), но распознана не будет.
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4823
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: sed: отрицание backreference в regex

Сообщение SLEDopit »

watashiwa_darede... писал(а):
21.05.2010 13:42
цифры?
да, опечатался (:
watashiwa_darede... писал(а):
21.05.2010 13:42
Исключения могут быть в том случае, если имеются перекрытия.
такие варианты исключены, поэтому спасибо большое. ваше решение полностью подходит.
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: sed: отрицание backreference в regex

Сообщение drBatty »

SLEDopit писал(а):
21.05.2010 12:13
в интернетах написано, что это делается так:
/(.*)word(?!\1)/

а в мануале написано, что sed не поддерживает такие выражения. и это не баг, а фича.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4823
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: sed: отрицание backreference в regex

Сообщение SLEDopit »

drBatty писал(а):
21.05.2010 14:23
и это не баг, а фича.
уж больно неудобная фича (:
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
Аватара пользователя
sash-kan
Администратор
Сообщения: 13939
Статус: oel ngati kameie
ОС: GNU

Re: sed: отрицание backreference в regex

Сообщение sash-kan »

SLEDopit писал(а):
21.05.2010 12:13
в интернетах написано, что это делается так:
/(.*)word(?!\1)/
это perlre. если не ошибаюсь, lookbehind-ом называется. или lookahead-ом.

конструкция

Код: Выделить всё

sed '/\(\(.\)_file_\2\)\{2\}/s/$/\*/'
удовлетворяет приведённому примеру и этому описанию:
SLEDopit писал(а):
21.05.2010 13:04
необходимо выделить строки, где до и после _file_ стоят одинаковые числа, т.е. из данных строк будет выделена только одна: 12_file_23_file_34
(помечает искомую строку звёздочкой)

SLEDopit писал(а):
21.05.2010 15:03
уж больно неудобная фича
это «фича» perlre. в sed её никто не будет «запихивать».

p.s. читайте Фридла, и будет вам счастье и мир во всём мире.
Писать безграмотно - значит посягать на время людей, к которым мы адресуемся, а потому совершенно недопустимо в правильно организованном обществе. © Щерба Л. В., 1957
при сбоях форума см.блог
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: sed: отрицание backreference в regex

Сообщение drBatty »

SLEDopit писал(а):
21.05.2010 15:03
уж больно неудобная фича

за то - быстрая.
sash-kan писал(а):
21.05.2010 15:15
это «фича» perlre. в sed её никто не будет «запихивать».

почему? вроде пытаются переделать sed... а если посмотреть исходник текущей версии, то видно, что можно включить perl-синтаксис... (у меня что-то не получилось)
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
ZyX
Сообщения: 355
ОС: Gentoo

Re: sed: отрицание backreference в regex

Сообщение ZyX »

sash-kan писал(а):
21.05.2010 15:15
SLEDopit писал(а):
21.05.2010 12:13
в интернетах написано, что это делается так:
/(.*)word(?!\1)/
это perlre. если не ошибаюсь, lookbehind-ом называется. или lookahead-ом.
Здесь он смотрит после (или впереди) текущей позиции — lookahead.
это «фича» perlre. в sed её никто не будет «запихивать».

А также огромного количества других perl’оподобных движков регулярных выражений. Присутствует ещё и в Vim’е.

Кстати, а зачем это было делать именно на sed? Если в том, что вы написали в первом сообщении заменить «sed -r '/.../d'» на «perl -p -i -e 'undef $_ unless /.../'», то всё работает. Ещё можно попробовать «grep -P '...'». Но для этого grep должен быть собран с поддержкой pcre.
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: sed: отрицание backreference в regex

Сообщение watashiwa_daredeska »

drBatty писал(а):
21.05.2010 16:38
за то - быстрая.
С backreference всё равно не быстрая, а sed поддерживает backreference.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: sed: отрицание backreference в regex

Сообщение drBatty »

watashiwa_darede... писал(а):
21.05.2010 18:13
С backreference всё равно не быстрая, а sed поддерживает backreference.

не всё равно. действительно, с br выражение невозможно скомпилировать перед поиском (потому-что оно меняется в процессе поиска), однако в любом случае поиск выполняется за один проход. А вот с пред(после)просмотром 1 проход часто невозможен, потому поиск выполняется в этом случае ещё медленнее (на практике часто намного медленнее).
ZyX писал(а):
21.05.2010 16:44
Ещё можно попробовать «grep -P '...'». Но для этого grep должен быть собран с поддержкой pcre.

ещё можно попробовать sed, с поддержкой pcre :)
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: sed: отрицание backreference в regex

Сообщение watashiwa_daredeska »

drBatty писал(а):
21.05.2010 18:30
однако в любом случае поиск выполняется за один проход.
Можно пруфлинк на алгоритм? Естественно, с сохранением исходного авторства — миллион баксов, всё-таки :) Однопроходный алгоритм Томпсона я знаю, но:
Backreferences. As mentioned earlier, no one knows how to implement regular expressions with backreferences efficiently, though no one can prove that it's impossible either. (Specifically, the problem is NP-complete, meaning that if someone did find an efficient implementation, that would be major news to computer scientists and would win a million dollar prize.)
Спасибо сказали:
Аватара пользователя
ZyX
Сообщения: 355
ОС: Gentoo

Re: sed: отрицание backreference в regex

Сообщение ZyX »

drBatty писал(а):
21.05.2010 18:30
ZyX писал(а):
21.05.2010 16:44
Ещё можно попробовать «grep -P '...'». Но для этого grep должен быть собран с поддержкой pcre.

ещё можно попробовать sed, с поддержкой pcre :)

Grep с поддержкой pcre получается при указании соответствующего USE флага устанавливается без дополнительных ухищрений и отлично работает. Sed’а с поддержкой pcre в репозитории нет, а, судя по сообщениям выше, я от того потерял совсем немного.
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4823
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: sed: отрицание backreference в regex

Сообщение SLEDopit »

sash-kan писал(а):
21.05.2010 15:15
sed '/\(\(.\)_file_\2\)\{2\}/s/$/\*/'
Спасибо, но все же это немного не то. Вариант watashiwa_daredeska больше подходит.
Просто если я напишу вот так:

Код: Выделить всё

sed -r "/((.)_file_\2){${#CONST}}/s/$/\*/"
то перестает работать при длине CONST > 2 (просто у меня не всегда только 2 _file_ в строке, заранее точно неизвестно их количество, а длина CONST соотвествует количеству _file_.
watashiwa_daredeska писал(а):
21.05.2010 19:15
(Specifically, the problem is NP-complete, meaning that if someone did find an efficient implementation, that would be major news to computer scientists and would win a million dollar prize.)
Эх, не тем я занимаюсь (:
ZyX писал(а):
21.05.2010 16:44
Ещё можно попробовать «grep -P '...'».
Попробовал. Только он, по ходу, с русскими символами особо работать не умеет. Цифры и латиница - нормально, русские - ничего не выдает.
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: sed: отрицание backreference в regex

Сообщение drBatty »

watashiwa_darede... писал(а):
21.05.2010 19:15
Можно пруфлинк на алгоритм? Естественно, с сохранением исходного авторства — миллион баксов, всё-таки :)

info sed
вы видимо не поняли... старые ссылки просто сохраняются в структуре наподобие стека. В sed допустимо всего 10 ссылок, потому есть жестокие ограничения... При таких условиях даже $1000 не получить...
алгоритм - в любом дистрибутиве.
watashiwa_darede... писал(а):
21.05.2010 19:15
Specifically, the problem is NP-complete, meaning that if someone did find an efficient implementation, that would be major news to computer scientists and would win a million dollar prize.

угу. если N*M будет большой новостью. а строчка*10 (максимум) - это как-то не интересно...
ZyX писал(а):
21.05.2010 22:38
Sed’а с поддержкой pcre в репозитории нет, а, судя по сообщениям выше, я от того потерял совсем немного.

согласен. ИМХО sed с перловыми RE ещё и глючит... В любом случае - лучше использовать perl, если это действительно надо.
SLEDopit писал(а):
22.05.2010 01:12
Попробовал. Только он, по ходу, с русскими символами особо работать не умеет. Цифры и латиница - нормально, русские - ничего не выдает.

попробуйте перевести в однобайтовую кодировку, а уж потом обработать. sed умеет и так... но лучше так не делать...
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
ZyX
Сообщения: 355
ОС: Gentoo

Re: sed: отрицание backreference в regex

Сообщение ZyX »

SLEDopit писал(а):
22.05.2010 01:12
ZyX писал(а):
21.05.2010 16:44
Ещё можно попробовать «grep -P '...'».
Попробовал. Только он, по ходу, с русскими символами особо работать не умеет. Цифры и латиница - нормально, русские - ничего не выдает.

Тоже есть такая проблема, но только если со строками надо что-то делать (например, напечатать только часть строки из-за флага -o). Если надо просто решить, печатать ли строку или нет, то всё нормально. grep-2.5.4-r1 USE="nls pcre".
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: sed: отрицание backreference в regex

Сообщение watashiwa_daredeska »

drBatty писал(а):
22.05.2010 02:03
угу. если N*M будет большой новостью. а строчка*10 (максимум) - это как-то не интересно...
О чём это Вы? Какие N*M?

Shell

$ for i in $(seq 20 2 ${#a}); do \ b=${a:0:$i}; \ echo $b; \ time (echo $b | sed -rn 's/^(.+)(.+)(\1\2|\2\1)+$/\1 \2/p'); \ done ababababbaabababbaba a b real 0m0.666s user 0m0.664s sys 0m0.000s ababababbaabababbabaab a b real 0m2.647s user 0m2.632s sys 0m0.000s ababababbaabababbabaabab a b real 0m16.262s user 0m16.261s sys 0m0.000s ababababbaabababbabaababba a b real 1m16.733s user 1m16.721s sys 0m0.012s ababababbaabababbabaababbaab a b real 7m25.733s user 7m25.612s sys 0m0.080s ababababbaabababbabaababbaabab <тут я уже не дождался>
Как видите, в регекспе всего 2 группы \1 и \2, строчка растет линейно на 2 символа, а время экспоненциально. Так что, никаких N*M.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: sed: отрицание backreference в regex

Сообщение drBatty »

watashiwa_darede... писал(а):
22.05.2010 10:54
а время экспоненциально.

ИМХО должно расти квадратично, а вовсе не экспоненциально.
Хотя в вашем скрипте - да, экспоненциально.
Вот если-бы вы искали в строке длинной M последовательность из N символов, то время было-бы N*M, у вас-же N с каждым просмотренным символом увеличивается, и получается экспонента (точнее конечный ряд).

т.е. поиск в строке(точнее в не просмотренном хвосте) \1 производится довольно просто - sed знает где начинается \1, и хранит указатель на эту br. Ну и затем тупо проверяет символы в строке на совпадение с ссылками в \1. (могу и напутать, смотрел этот код с пол-года назад).

т.о. если мы ищем шаблон /ABCD/ в строке из N символов, то каждый символ(в строке) будет просмотрен 1 раз - шаблон скомпиллируется. А вот если искать шаблон /(.)\1/, то каждый символ будет просмотрен дважды (кроме первого) на совпадение с прошлым символом. Однако, вся строка будет просмотрена всего 1 раз.

В данном случае sed может запомнить 9 указателей на ссылки, но всё сильно усложнится, если сделать пред(после) просмотр как в перле.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: sed: отрицание backreference в regex

Сообщение watashiwa_daredeska »

drBatty писал(а):
22.05.2010 12:06
А вот если искать шаблон /(.)\1/
Это очень хороший шаблон — тут группа начинается и заканчивается в фиксированном месте. Если /.*(.*)\1/, то всё гораздо хуже — каждый символ может быть просмотрен N^2 раз (перепробовать разные начала и концы группы \1), пока не сматчится это самое \1. Ну, либо соответствующее увеличение кол-ва памяти. В общем, это уже далеко не тот простой DFA из алгоритма Томпсона.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: sed: отрицание backreference в regex

Сообщение drBatty »

watashiwa_darede... писал(а):
22.05.2010 13:51
Это очень хороший шаблон — тут группа начинается и заканчивается в фиксированном месте. Если /.*(.*)\1/, то всё гораздо хуже — каждый символ может быть просмотрен N^2 раз (перепробовать разные начала и концы группы \1), пока не сматчится это самое \1. Ну, либо соответствующее увеличение кол-ва памяти.

полностью согласен. тут алгоритм надо менять.
вот ещё пример: отрезание ровно половины строки c одинаковыми символами.

Shell

$ echo 'ZZZZZZZZZZZZZZZZZZZ' | sed -r 's/(.*)\1/\1/' ZZZZZZZZZZ

тут находится N/2 совпадений, и берётся последнее, самое большое. Конечно поделить строку пополам можно намного быстрее. (за время пропорциональное O(1)). вот только sed этого не умеет :(
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: sed: отрицание backreference в regex

Сообщение watashiwa_daredeska »

drBatty писал(а):
22.05.2010 14:16
полностью согласен. тут алгоритм надо менять.
Тут надо отказываться от backreferences :)
На самом деле, я ошибся — там N^3: N (исходные, по Томпсону) * N (перебор точек начала группы) * N (перебор точек конца). Очередная группа с backreference даёт ещё *N^2 в общем случае, но может и N, если начало совпадает с концом предыдущей, например. Да, существуют оптимизации для часто используемых случаев, но они не полны и всегда можно сочинить ситуацию, когда эти оптимизации просядут и получится полноценный перебор со всеми вытекающими.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: sed: отрицание backreference в regex

Сообщение drBatty »

watashiwa_darede... писал(а):
22.05.2010 15:16
Да, существуют оптимизации для часто используемых случаев, но они не полны и всегда можно сочинить ситуацию, когда эти оптимизации просядут и получится полноценный перебор со всеми вытекающими.

с другой стороны мне на практике обычно попадаются случаи, когда намного быстрее сделать без br. Как в делении пополам - ведь sed в любой момент знает длину строки, и может с лёгкостью отрезать половину (наверное за 5-10 тактов). :(
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали: