Можем ли мы обойтись без ленивых квантификаторов? - PullRequest
4 голосов
/ 04 октября 2011

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

СтрокаЯ хочу, чтобы процесс состоял из подстрок, разделенных скоростью слова, например:

anfhwe9.<<76xnf9247 rate 7dh3_29snpq+074j rate 48jdhsn3gus8 rate

Я хочу заменить эти подстроки (кроме слова ' rate ') на 3 черты(---) каждый;результат должен быть:

---rate---rate---rate

Из того, что я понимаю (я не знаю Perl), это можно легко сделать с помощью ленивых квантификаторов.В vim есть ленивые квантификаторы;Я сделал это с помощью этой команды

:s/.\{-}rate/---rate/g

, где \{-} указывает vim соответствовать как можно меньшему числу.

Однако vim - текстовый редактор, и мне нужно запустить скрипт на многихмашины, на некоторых из которых не установлен Perl.Это также может быть решено, если вы можете указать регулярному выражению, что оно не соответствует атомной группировке, такой как .*[^(rate)]rate, но это не сработало.

Есть идеи, как этого добиться с помощью регулярного выражения POSIX, или это невозможно?

Ответы [ 6 ]

3 голосов
/ 04 октября 2011

В таком случае я бы использовал split ():

perl -n -e 'print join ("rate", ("---") x split /rate/)' [input-file]
2 голосов
/ 04 октября 2011

Есть ли символы, которые гарантированно не будут присутствовать на входе? Например, если '!' не может произойти, вы можете преобразовать ввод для замены этого уникального символа, а затем выполнить глобальную замену преобразованного ввода:

sed 's/ rate /!/g' < input | sed -e 's/[^!]*/---/g' -e 's/!/rate/g'

Другой альтернативой является использование команды split в awk аналогично предложение perl выше, предполагая, что awk более надежен, чем perl.

awk '
{   ans="---"
    n=split($0, x, / rate /);
    while ( n-- ) { ans = ans "rate---";}
    print ans
}'
2 голосов
/ 04 октября 2011

Нелегко без использования ленивых квантификаторов или негативных предупреждений (ни один из которых не поддерживает POSIX), но, похоже, это работает.

([^r]*((r($|[^a]|a([^t]|$)|at([^e]|$))))?)+rate

Я смутно припоминаю, что классы символов POSIX немного привередливы. Возможно, вам придется изменить классы символов в этом регулярном выражении, если они еще не совместимы с POSIX.

1 голос
/ 04 октября 2011

Тот факт, что вы не заботитесь о содержимом подстрок, открывает много возможностей.Например, чтобы добавить к предложению Боба Лиеда, даже если «!»может появиться на входе, вы можете начать с изменения его на что-то другое:

0 голосов
/ 04 октября 2011

или awk 'BEGIN {OFS=FS="rate"} {for (i=1; i<=NF-1; i++) {$i = "---"}; print}'

0 голосов
/ 04 октября 2011

С awk :

awk -Frate '{ 
  for (i = 0; ++i <= NF;) 
    $i = (i == 1 || i == NF) && $i == x ? x : "---" 
  }1' OFS=rate infile   
...