Por que '[az] *' corresponde a cadeias não alfabéticas?

9

Eu tenho um arquivo alphanumcom estas duas linhas:

123 abc
this is a line

Estou confuso sobre o motivo pelo qual, quando executo sed 's/[a-z]*/SUB/' alphanum, recebo a seguinte saída:

SUB123 abc
SUB is a line

Eu estava esperando:

123 SUB
SUB is a line

Encontrei uma correção (use em sed 's/[a-z][a-z]*/SUB/'vez disso), mas não entendo por que ela funciona e a minha não.

Você pode ajudar?

Fakher Mokadem
fonte
@ Kamaraj, esse é semelhante, mas tem confusão de padrões de shell vs expressões regulares no topo (e as respostas concentram-se no primeiro, já que é isso que o ls foo*lá usa). Mas, de qualquer maneira, se você encontrar perguntas duplicadas, acho que também poderá sinalizá-las como tal.
Ilkkachu
confira regexr.com para visuais ao vivo e explica
ROZZA
@RozzA Observe que o site ao qual você vincula suporta expressões regulares Javascript e Perl, não expressões regulares POSIX.
Kusalananda

Respostas:

28

O padrão [a-z]*corresponde a zero ou mais caracteres no intervalo apara z(os caracteres reais dependem da localidade atual). Existem zero desses caracteres no início da string 123 abc(ou seja, o padrão corresponde) e também quatro deles no início de this is a line.

Se você precisar de pelo menos uma correspondência, use [a-z][a-z]*ou [a-z]\{1,\}, ou ative expressões regulares estendidas com sed -Ee use [a-z]+.

Para visualizar onde o padrão corresponde, adicione parênteses em torno de cada correspondência:

$ sed 's/[a-z]*/(&)/' file
()123 abc
(this) is a line

Ou, para ver todas as correspondências nas linhas:

$ sed 's/[a-z]*/(&)/g' file
()1()2()3() (abc)
(this) (is) (a) (line)

Compare esse último resultado com

$ sed -E 's/[a-z]+/(&)/g' file
123 (abc)
(this) (is) (a) (line)
Kusalananda
fonte
7
Tecnicamente [a-z]jogos em elementos que podem ser feitas de mais de um personagem. Por exemplo, em alguns locais húngaros, [a-z]jogos emdzs
Stéphane Chazelas
12

Porque *corresponde a zero ou mais repetições do átomo anterior, e todos os mecanismos de expressão regular tentam encontrar a primeira correspondência. Há uma subcadeia de exatamente zero letras no início da sua string, então é aí que ela corresponde. No caso em que a sequência começa com uma letra, *corresponde ao maior número possível, mas isso é secundário para encontrar a correspondência mais à esquerda.

Correspondências de comprimento zero podem ser um pouco problemáticas e, como você viu, a solução é modificar o padrão para que exija pelo menos um caractere. Com regexes estendidas, você pode +:sed -E 's/[a-z]+/SUB/'

Por diversão, tente:

echo 'less than 123 words' | sed 's/[0-9]*/x/g'
ilkkachu
fonte