spamsink: (Default)
spamsink ([personal profile] spamsink) wrote2021-06-14 08:07 pm

Программистский вопрос; возможно, тупой

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



Легко написать регулярное выражение, которое находит строки, содержащие "foo" слева от "bar", и чтобы "qux" было между ними: foo.*qux.*bar (не будем сейчас вдаваться в подробности, как именно распределятся символы строки по этим ".*", если вхождений "foo", "bar" или "qux" в строке несколько).

Вопрос вот в чём: есть ли где-нибудь такое расширение языка регулярных выражений, которое позволило бы компактно записать условие найти строки, содержащие "foo" слева от "bar", и чтобы между ними не было "qux"?

UPD: На самом деле здесь две задачи. Первая: паттерну должны удовлетворять строки /foo(.*)bar/ (т.е. .* захватывает всё между первым вхождением foo и последним вхождением bar в строке), такие, что в захваченной строке не содержится qux; вторая: паттерну должны удовлетворять строки, в которых найдутся такие вхождения foo и bar, между которыми нет qux.

Строка "foo qux foo xxx bar qux bar" не удовлетворяет первому паттерну, но удовлетворяет второму.


Похоже, negative lookahead assertions решают одну из двух задач
juan_gandhi: (Default)

[personal profile] juan_gandhi 2021-06-15 03:27 am (UTC)(link)

.* придется убрать.

foo[^q](q[^u](qu[^x]*)?)?bar

Ну, может, скобок убавить.

juan_gandhi: (Default)

[personal profile] juan_gandhi 2021-06-15 03:49 am (UTC)(link)

О блин. Ну да, после закрывающей квадратной скобки.

foo[^q]*(q[^u]*(qu[^x]*)?)?bar

А что делать, что делать. Мы ж изготовляем конечный автомат.

vit_r: default (Default)

[personal profile] vit_r 2021-06-15 05:13 am (UTC)(link)
Части регулярных выражений можно распихать по переменным, а потом собирать из них.

[personal profile] sassa_nf 2021-06-15 05:12 am (UTC)(link)
I think that's not quite right. You want
foo([^q]|q[^u]|qu[^x])*bar
, but they have lookaheads now. (We've done dirty "close tag" matching "open tag" that way, with obvious issues)

[personal profile] sassa_nf 2021-06-15 04:29 am (UTC)(link)
There are various lookaheads and lookbehinds supported now:
foo((?!qux).)*bar
might work (haven't tested).
Edited 2021-06-15 04:39 (UTC)
lev: (Default)

[personal profile] lev 2021-06-15 04:41 am (UTC)(link)
matches fooquxbar though (original with dot in front)
Edited 2021-06-15 04:42 (UTC)

[personal profile] sassa_nf 2021-06-15 08:40 am (UTC)(link)
JS:
> x = /foo((?!qux).)*bar/
/foo((?!qux).)*bar/
> x.test('foo bar')
true
> x.test('foo qux bar')
false
> x.test('foo xxx bar qux bar')
true
may be language specific, eg "?!" not implemented?

$ python3
Python 3.9.4 (default, Apr  5 2021, 01:49:30) 
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import re
>>> x = re.compile('foo((?!qux).)*bar')
>>> x.match('foo bar')
<re.Match object; span=(0, 7), match='foo bar'>
>>> x.match('foo qux bar')
None
>>> x.match('foo xxx bar qux bar')
<re.Match object; span=(0, 11), match='foo xxx bar'>
Edited 2021-06-15 08:49 (UTC)
dluciv: (Default)

[personal profile] dluciv 2021-06-15 05:30 am (UTC)(link)

Вообще у меня что-то из такого таки работало, но не помню, что, где и в насколько частном случае https://stackoverflow.com/q/2404010/539470

Тред не читал @ сразу отвечал

Edited 2021-06-15 05:30 (UTC)

[personal profile] sassa_nf 2021-06-15 08:02 pm (UTC)(link)
> Все решения

Is there a reason, like a specification for regex with negative lookahead? Javascript and python work just fine for foo xxx bar qux bar.
sab123: (Default)

[personal profile] sab123 2021-06-15 06:36 am (UTC)(link)
Вроде в Перле есть?
vanja_y: (Default)

[personal profile] vanja_y 2021-06-15 07:49 pm (UTC)(link)
Я обычно делаю что-то вроде

sed 's/qux/ß/g' | grep 'foo[^ß]*bar' | sed 's/ß/qux/g'


Вместо ß можно использовть что-нибудь более экзотическое, если текст на немецком.