Как использовать [\ w] + в регулярном выражении в sed?


24

Я нахожусь на Windows, но я предполагаю, что мой вопрос все еще правильно помещен здесь.

C:\Users\User>grep --version
GNU grep 2.6.3

C:\Users\User>sed --version
GNU sed version 4.2.1

Я заметил, что следующие работы (вывод here):

echo here | grep -E "\w+"
echo here | grep -E "[her]+"

Но это не работает (ничего не выводя):

echo here | grep -E "[\w]+"

Это снова делает (вывод here):

echo here | grep -P "[\w]+"

Так [\w]что - то конкретное для Perl регулярных выражений, я полагаю. Это верно?

Итак, поговорим sed. Это работает (вывод gone):

echo here | sed -r "s/\w+/gone/"
echo here | sed -r "s/[her]+/gone/"

И опять же, это не (вывод here):

echo here | sed -r "s/[\w]+/gone/"

Теперь, как я могу активировать регулярные выражения Perl для sed - есть ли способ?

Ответы:


11

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

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

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

В POSIX BRE и ERE у вас есть [:alnum:]класс персонажа. Это соответствует буквам и цифрам в вашей локали (обратите внимание, что часто включает в себя гораздо больше, чем, a-zA-Z0-9если только локаль не C).

Так:

grep -x '[[:alnum:]_]\{1,\}'

соответствует одному или нескольким alnum или _.

[\w]требуется POSIX для соответствия с обратной косой чертой или w. Таким образом, вы не найдете grepили sedреализации, где это доступно (если только через нестандартные опции).

\wPOSIX не определяет поведение для одних, поэтому реализациям разрешено делать то, что они хотят. GNU grepдобавил, что давно.

В GNU grepраньше был собственный движок регулярных выражений, однако теперь он использует GNU libc (хотя он и встраивает свою собственную копию).

Он предназначен для совпадения чисел и подчеркивания в вашем регионе. Однако в настоящее время в нем есть ошибка, заключающаяся в том, что он соответствует только однобайтовым символам (например, не é в локали UTF-8, даже если это явно буква и даже соответствует é во всех локалях, где é является одиночным персонаж).

Также есть \wоператор регулярного выражения в регулярном выражении perl и в PCRE. PCRE / perl не являются регулярными выражениями POSIX, это просто еще одна вещь.

Теперь, когда GNU grep -Pиспользует PCRE, у него та же проблема, что и без -P. Это можно обойти там, хотя с помощью (*UCP)(хотя это также имеет побочные эффекты в локалях не-UTF8).

GNU sedтакже использует регулярные выражения GNU libc для своих собственных регулярных выражений. Он использует его таким образом, что в нем нет той же ошибки, что и в GNU grep.

GNU sedне поддерживает PCRE. В коде есть некоторые доказательства того, что он был предпринят ранее, но, похоже, он больше не стоит на повестке дня.

Если вы хотите регулярные выражения Perl, просто используйте perlхотя.

В противном случае, я бы сказал, что вместо того, чтобы пытаться полагаться на поддельную нестандартную функцию вашей конкретной реализации sed/ grep, лучше придерживаться стандарта и использовать его [_[:alnum:]].


[_[:alnum:]]хороший обходной путь, который позволяет мне расширять его так же, как [\w/]( [_[:alnum:]/]в этом случае).
Берс

1
Этот ответ сейчас устарел в отношении ограничений GNU grep.
Стефан

7

Вы правы - \wэто часть PCRE - perl-совместимых регулярных выражений. Это не часть «стандартного» регулярного выражения. http://www.regular-expressions.info/posix.html

Некоторые версии sedмогут поддержать его, но я хотел бы предложить самый простой способ это просто использовать perlв sedрежиме, указав -pфлаг. (Вместе с -e). (Подробнее в perlrun)

Но вам не нужно []обходиться этим в этом примере - это для групп правильных вещей.

echo here  | perl -pe 's/\w+/gone/'

Или на Windows:

C:\>echo here  | perl -pe "s/\w+/gone/"
gone
C:\>echo here  | perl -pe "s/[\w\/]+/gone/"
gone

Смотрите perlreдля более PCRE вещи.

Вы можете получить Perl здесь: http://www.activestate.com/activeperl/downloads


Обратите внимание на разницу между \wи [\w]в моем вопросе. Я обновлю его выводами каждой команды, чтобы было понятно, какая из них работает, а какая нет. В частности, sedпонимает \w, но нет [\w]. Кроме того, мне нужно [\w]работать, потому что я хочу использовать, [\w/]например.
Берс

В этом случае это, вероятно, проблема с цитированием. В любом случае - perlможете сделать это :).
Sobrique

Благодарность! Ответ Стефана Чазеласа немного ближе к тому, что я просил (так как у меня не установлен perl - я думаю, пользователь du * b для Windows), поэтому я принял его ответ.
Берс

Это нормально, но я бы порекомендовал установить Perl на Windows. Это одно из первых, что касается меня, и я нахожу это чрезвычайно полезным.
Sobrique

\wбыл в GNU grep (в 80-х) до того, как быть в Perl, а в GNU emacs, вероятно, даже до этого.
Стефан Шазелас

1

Я подозреваю, что grepи sedпо-разному решаем, когда применять []и когда расширять \w. В Perl регулярное выражение \wозначает любой символ слова и []определяет группу для применения любого из символов в качестве совпадения. Если вы «развернете» \wранее, то []это будет класс символов всех символов слова. Если вместо этого вы []сначала сделаете, у вас будет класс символов с двумя символами, \и wон будет соответствовать любому шаблону, содержащему один или несколько из этих двух символов.

Таким образом, кажется, что sedон видит []и обрабатывает его как содержащий точные символы для сопоставления вместо того, чтобы соблюдать особую последовательность, \wкак perlи grepделают. Конечно, []в этом примере они совершенно не нужны, но можно представить себе случаи, когда это было бы важно, но тогда вы могли бы заставить его работать с паренами и / или.


Я был бы удивлен, если бы это было так. \ это escape-код, и вы бы использовали его для экранирования. По своей сути это означает, что он должен иметь более высокий приоритет, чем любая другая вещь. Я думаю, что более вероятно, что это не реализовано, потому что \wне является частью спецификации регулярных выражений
Sobrique

Ну, эмпирически это похоже на случай использования gnu sed для меня: echo whe\\ere | sed -r 's/[\w]+/gone/gдает мне, gonehegoneereкак будто он соответствует каждому из ` and w` и делает замену
Эрик Ренуф

Я могу подтвердить то, что видит Эрик Ренуф. Итак, мы хотим как-нибудь убрать обратную косую черту? :)
берс

Я не думаю, что это правильный ответ. Sed просто не поддерживает смешивание различных типов определений классов символов, поэтому ответ таков: если вы должны использовать оба типа классов символов, выберите другой инструмент или если вы выбираете sed, используйте синтаксис, который он поддерживает
Эрик Ренуф,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.