Como usar [\ w] + na expressão regular em sed?

24

Estou no Windows, mas acho que minha pergunta ainda está correta aqui.

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

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

Notei que os seguintes trabalhos (saída here):

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

Mas, isso não funciona (não produz nada):

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

Isso faz novamente (saída here):

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

Então, [\w]é algo específico para expressões regulares do Perl, presumo. Isso está correto?

Então vamos conversar sed. Isso funciona (saída gone):

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

E, novamente, isso não ocorre (saída here):

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

Agora, como posso ativar expressões regulares Perl para sed - existe alguma maneira?

bers
fonte

Respostas:

11

Diferentes ferramentas e suas versões suportam diferentes variantes de expressões regulares. A documentação de cada um lhe dirá o que eles suportam.

Existem padrões para que você possa confiar em um conjunto mínimo de recursos disponíveis em todos os aplicativos em conformidade.

Por exemplo, todas as implementações modernas sede grepimplementam expressões regulares básicas, conforme especificado pelo POSIX (pelo menos uma versão ou outra do padrão, mas esse padrão não evoluiu muito nesse sentido nas últimas décadas).

No POSIX BRE e ERE, você tem a [:alnum:]classe de caracteres. Isso corresponde a letras e dígitos no seu código de idioma (observe que geralmente inclui muito mais do que a-zA-Z0-9, a menos que o código de idioma seja C).

Tão:

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

corresponde a um ou mais alnums ou _.

[\w]é requerido pelo POSIX para corresponder à barra invertida ou w. Portanto, você não encontrará uma grepou sedimplementação onde esteja disponível (a menos que seja através de opções fora do padrão).

O comportamento \wsozinho não é especificado pelo POSIX, portanto, as implementações podem fazer o que desejam. O GNU grepacrescentou isso há muito tempo.

O GNU grepcostumava ter seu próprio mecanismo de expressão regular, mas agora usa o mecanismo do GNU libc (embora ele incorpore sua própria cópia).

Ele serve para combinar alnums e sublinhado em seu local. No entanto, atualmente existe um erro, pois corresponde apenas a caracteres de byte único (por exemplo, não é em um código de idioma UTF-8, mesmo que isso seja claramente uma letra e mesmo que corresponda a em todas as localidades em que é um único personagem).

Também existe um \woperador regexp no perl regexp e no PCRE. PCRE / perl não são expressões regulares POSIX, são apenas outra coisa.

Agora, com a maneira como o GNU grep -Pusa o PCRE, ele tem o mesmo problema que sem -P. No entanto, pode ser trabalhado por aí usando (*UCP)(embora isso também tenha efeitos colaterais em locais não UTF8).

O GNU sedtambém usa os regexs do GNU libc para seus próprios regexps. Ele o usa de tal maneira que não possui o mesmo bug que o GNU grep.

O GNU sednão suporta PCREs. Há alguma evidência no código de que ele foi tentado antes, mas parece que não está mais na agenda.

Se você quiser expressões regulares do Perl, use-as perl.

Caso contrário, eu diria que, em vez de tentar confiar em um recurso não-padrão falso de sua implementação específica de sed/ grep, seria melhor seguir o padrão e o uso [_[:alnum:]].

Stéphane Chazelas
fonte
[_[:alnum:]]é uma boa solução alternativa que me permite estendê-la exatamente como [\w/]( [_[:alnum:]/]nesse caso).
BERS
11
Esta resposta está desatualizada no que diz respeito às limitações do GNU grep.
Stéphane Chazelas
7

Você está correto - \wfaz parte das expressões regulares compatíveis com PCRE - perl. Porém, não faz parte da regex 'padrão'. http://www.regular-expressions.info/posix.html

Algumas versões sedpodem suportá-lo, mas eu sugiro que a maneira mais fácil é usar apenas perlno sedmodo, especificando o -psinalizador. (Junto com o -e). (Mais detalhes em perlrun)

Mas você não precisa []contornar esse exemplo - isso é para grupos de coisas válidas.

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

Ou no Windows:

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

Veja perlrepara mais informações sobre o PCRE.

Você pode obter o perl aqui: http://www.activestate.com/activeperl/downloads

Sobrique
fonte
Observe a diferença entre \we [\w]na minha pergunta. Vou atualizá-lo com saídas de cada comando para deixar claro qual deles está funcionando e qual não está. Em particular, sedentende \w, mas não [\w]. Além disso, preciso [\w]trabalhar porque quero usar, [\w/]por exemplo.
BERS
Nesse caso, é provavelmente um problema de cotação. De qualquer maneira - perlpode fazê-lo :).
Sobrique
Obrigado! A resposta de Stéphane Chazelas está um pouco mais próxima do que eu pedi (já que eu não tenho o perl instalado - um usuário du * b do Windows, eu acho), então eu aceitei a resposta dele.
BERS
Tudo bem - mas eu recomendo instalar o Perl no Windows. É uma das primeiras coisas que acontecem nas minhas, e acho extremamente útil.
Sobrique
\westava no GNU grep (nos anos 80) antes de estar em perl e no GNU emacs provavelmente antes mesmo disso.
Stéphane Chazelas
1

Eu suspeito que grepe sedesteja decidindo diferentemente quando aplicar o []e quando expandir o \w. Em perl regex \wsignifica qualquer caractere de palavra e []define um grupo para aplicar qualquer um dos caracteres como uma correspondência. Se você "expandir" o \wanterior [], será uma classe de caracteres de todos os caracteres da palavra. Se, em vez disso, []primeiro você terá uma classe de caracteres com dois caracteres \e, wportanto, corresponderá a qualquer padrão que contenha um ou mais desses dois caracteres.

Parece que sedé vê- []lo e tratá-lo como contendo os caracteres exatos a serem correspondidos em vez de honrar a sequência especial \wcomo perle o grepfaz. É claro que []são completamente desnecessários neste exemplo, mas talvez se possa imaginar casos em que isso seria importante, mas você poderia fazê-lo funcionar com parênteses e ors.

Eric Renouf
fonte
Eu ficaria surpreso se assim fosse. \ é um código de escape e você o usaria para escapar de delimitadores. Inerentemente, isso significa que deve ter uma precedência mais alta do que qualquer outra coisa. Acho mais provável que ele não está implementada porque \wnão é parte da especificação expressão regular
Sobrique
Bem, empiricamente parece ser o caso, utilizando o GNU sed para mim: echo whe\\ere | sed -r 's/[\w]+/gone/gdá-me gonehegoneerecomo se está combinando cada um dos ` and w` e fazer a substituição
Eric Renouf
Posso confirmar o que Eric Renouf está vendo. Então, queremos tirar a barra invertida de alguma forma? :)
bers
Não acho que seja a resposta certa. O Sed simplesmente não suporta misturar os diferentes tipos de definições de classes de caracteres, então a resposta é: se você deve usar os dois tipos de classes de caracteres, escolha outra ferramenta, ou se você estiver escolhendo o sed, use a sintaxe que ele suporta
Eric Renouf