Dlaczego „[az] *” pasuje do łańcuchów niealfabetycznych?

9

Mam plik alphanumz tymi dwiema liniami:

123 abc
this is a line

Nie jestem pewien, dlaczego po uruchomieniu sed 's/[a-z]*/SUB/' alphanumotrzymuję następujące dane wyjściowe:

SUB123 abc
SUB is a line

Spodziewałem się:

123 SUB
SUB is a line

Znalazłem poprawkę (użyj sed 's/[a-z][a-z]*/SUB/'zamiast tego), ale nie rozumiem, dlaczego to działa, a moje nie.

Możesz pomóc?

Fakher Mokadem
źródło
@Kamaraj, ten jeden jest podobny, ale ma na wierzchu zamieszanie wzorców względem wyrażeń regularnych (a odpowiedzi koncentrują się na tym pierwszym, ponieważ tego ls foo*tam używa). Ale w każdym razie, jeśli znajdziesz pytania, które są duplikatami, myślę, że powinieneś być w stanie je również oznaczyć jako takie.
ilkkachu
sprawdź regexr.com, aby zobaczyć wideo na żywo i wyjaśnia
RozzA
@RozzA Należy pamiętać, że witryna, do której prowadzi łącze, obsługuje wyrażenia regularne JavaScript i Perl, a nie wyrażenia regularne POSIX.
Kusalananda

Odpowiedzi:

28

Wzór [a-z]*dopasowuje zero lub więcej znaków w zakresie ado z( rzeczywiste znaki zależą od bieżących ustawień regionalnych). Na początku łańcucha jest zero takich znaków 123 abc(tzn. Wzorzec pasuje), a także cztery z nich na początku this is a line.

Jeśli trzeba co najmniej jeden mecz, a następnie użyć [a-z][a-z]*lub [a-z]\{1,\}, lub włączyć rozszerzonych wyrażeń regularnych z sed -Ei wykorzystanie [a-z]+.

Aby wizualizować, gdzie wzór pasuje, dodaj nawiasy wokół każdego dopasowania:

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

Lub, aby zobaczyć wszystkie dopasowania w liniach:

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

Porównaj ten ostatni wynik z

$ sed -E 's/[a-z]+/(&)/g' file
123 (abc)
(this) (is) (a) (line)
Kusalananda
źródło
7
Technicznie [a-z]pasuje do zestawiania elementów, które mogą być złożone z więcej niż jednej postaci. Na przykład w niektórych lokalizacjach na Węgrzech [a-z]mecze wdzs
Stéphane Chazelas
12

Ponieważ *dopasowuje zero lub więcej powtórzeń poprzedniego atomu, a wszystkie silniki wyrażeń regularnych próbują znaleźć pierwsze dopasowanie. Na początku łańcucha znajduje się podłańcuch dokładnie zerowych liter, więc tam pasuje. W przypadku, gdy ciąg zaczyna się od litery, *dopasowuje tyle, ile może, ale jest to drugorzędne znaczenie dla znalezienia dopasowania najbardziej na lewo.

Dopasowania o zerowej długości mogą być nieco problematyczne, a jak zauważyłeś, rozwiązaniem jest zmodyfikowanie wzorca, tak aby wymagał co najmniej jednego znaku. Dzięki rozszerzonym wyrażeniom regularnym możesz +:sed -E 's/[a-z]+/SUB/'

Dla zabawy spróbuj:

echo 'less than 123 words' | sed 's/[0-9]*/x/g'
ilkkachu
źródło