Odpowiedziałem na to pytanie na SuperUser, które było związane z rodzajem wyrażeń regularnych używanych podczas grepowania wyniku.
Odpowiedź, którą podałem, była następująca:
tail -f log | grep "some_string.*some_string"
A potem w trzech komentarzach do mojej odpowiedzi @Bob napisał:
.*
jest chciwy i może uchwycić więcej, niż chcesz..*?
jest zwykle lepszy.
Wtedy to,
?
jest modyfikator na*
, co leniwy zamiast chciwy domyślnie. Zakładając PCRE.
Poszukałem wyszukiwarki Google PCRE
, ale nie mogłem zrozumieć, co to ma znaczyć w mojej odpowiedzi?
i na koniec to
Powinienem również zauważyć, że jest to wyrażenie regularne (domyślnie grep robi wyrażenie regularne POSIX), a nie glob powłoki.
Wiem tylko, czym jest Regex i bardzo podstawowe użycie go w poleceniu grep. Tak więc nie mogłem uzyskać żadnego z tych 3 komentarzy i mam na myśli następujące pytania:
- Jakie są różnice w wykorzystaniu
.*?
vs.*
? - Które jest lepsze i w jakich okolicznościach? Proszę podać przykłady.
Pomocne byłoby również zrozumienie komentarzy, gdyby ktokolwiek mógł
AKTUALIZACJA: Jako odpowiedź na pytanie Czym Regex różni się od Shell Globs? @Kusalananda podał ten link w swoim komentarzu.
UWAGA: W razie potrzeby przeczytaj moją odpowiedź na to pytanie, zanim odpowiesz na pytanie dotyczące kontekstu.
źródło
.*
vs..*?
Pytanie o „różnicę między wyrażeniami regularnymi a globami powłoki” zostało już rozwiązane na tej stronie.Odpowiedzi:
Ashok już zauważył różnicę między
.*
i.*?
, więc będę tylko podać kilka dodatkowych informacji.grep
(przy założeniu, że wersja GNU) obsługuje 4 sposoby dopasowania ciągów:grep
domyślnie używa BRE.BRE i ERE są udokumentowane w rozdziale Wyrażenia regularne POSIX, a PCRE jest udokumentowany na jego oficjalnej stronie internetowej . Należy pamiętać, że funkcje i składnia mogą się różnić w zależności od implementacji.
Warto powiedzieć, że ani BRE, ani ERE nie wspierają lenistwa :
Więc jeśli chcesz skorzystać z tej funkcji, musisz zamiast tego użyć PCRE:
Edytuj 1
.*
służy do dopasowania „najdłuższego” 1 możliwego wzoru..*?
służy do dopasowania „najkrótszego” 1 możliwego wzoru.Z mojego doświadczenia wynika, że najbardziej pożądanym zachowaniem jest zwykle drugie.
Załóżmy na przykład, że mamy następujący ciąg znaków i chcemy dopasować tylko tagi HTML 2 , a nie treść między nimi:
Teraz porównaj
.*
vs.*?
:1. Znaczenie „najdłuższego” i „najkrótszego” w kontekście wyrażenia regularnego jest nieco trudne, jak zauważył Kusalananda . Więcej informacji znajduje się w oficjalnej dokumentacji.
2. Nie zaleca się analizowania html z regex . To tylko przykład do celów edukacyjnych, nie używaj go w produkcji.
źródło
.*
vs.*?
?Załóżmy, że biorę ciąg taki jak:
can cats eat plants?
Użycie chciwości
c.*s
spowoduje dopasowanie całego ciągu, ponieważ zaczyna się odc
i kończy nas
, będąc chciwym operatorem, kontynuuje dopasowanie aż do końcowego wystąpienia s.Natomiast użycie leniwego
c.*?s
będzie pasować tylko do momentus
znalezienia pierwszego wystąpienia , tzncan cats
. Ciągu .Z powyższego przykładu możesz być w stanie zebrać, że:
„Chciwy” oznacza dopasowanie jak najdłuższego ciągu. „Leniwy” oznacza dopasowanie możliwie najkrótszego ciągu. Dodawanie
?
do kwantyfikatora jak*
,+
,?
, lub{n,m}
robi to leniwe.źródło
cats
, więc nie wymusza to ściśle „najkrótszego możliwego”.Ciąg można dopasować na kilka sposobów (od prostych do bardziej złożonych):
Jako ciąg statyczny (Załóżmy, że var = „Hello World!”):
shell
[ "$var" = "Hello World!" ] && echo yes
grep
echo "$var" | grep -F "Hello"
bash
grep -F "Hello" <<<"$var"
Jako glob:
shell
echo ./*
# wyświetla listę wszystkich plików w pwd. uderzenie
pocisku
case $var in (*Worl*) echo yes;; (*) echo no;; esac
[[ "$var" == *"Worl"* ]] && echo yes
Istnieją podstawowe i rozszerzone globusy. W
case
przykładzie wykorzystano podstawowe globusy.[[
Przykład bash używa rozszerzonych globów. Pierwsze dopasowanie pliku może być podstawowe lub rozszerzone w niektórych powłokach, takich jak ustawienieextglob
w bash. Oba są w tym przypadku identyczne. Grep nie mógł używać globów.Gwiazdka w glob oznacza coś innego niż gwiazdka w wyrażeniu regularnym :
glob
* matches any number (including none) of
dowolne postacie .regex
* matches any number (including none) of the
poprzedzający element .Jako podstawowe wyrażenie regularne (BRE):
sed
echo "$var" | sed 's/W.*d//'
# print: Cześć!
grep
grep -o 'W.*d' <<<"$var"
# print Świat!
Nie ma BRE w (podstawowych) powłokach ani awk.
Rozszerzone wyrażenia regularne (ERE):
bash
[[ "$var" =~ (H.*l) ]]
# match: Hello Worl
sed
echo "$var" | sed -E 's/(d|o)//g'
# print: Hell Wrl!
awk
awk '/W.*d/{print $1}' <<<"$var"
# print: Hello
grep
grep -oE 'H.*l' <<<"$var"
# print: Hello Worl
Wyrażenia regularne kompatybilne z Perlem:
grep
grep -oP 'H.*?l
# print: Hel
Tylko w PCRE a
*?
ma określone znaczenie składniowe.To sprawia, że gwiazdka jest leniwa (niewdzięczność): lenistwo zamiast chciwości .
To tylko wierzchołek góry lodowej, są zachłanni, leniwi , uległi lub pozytywni . Istnieją również lookahhead i lookbeind, ale nie dotyczą one gwiazdki
*
.Istnieje alternatywa, aby uzyskać taki sam efekt, jak niechciane wyrażenie regularne:
Pomysł jest bardzo prosty: nie używaj kropki
.
, zaneguj następny znak do dopasowania[^o]
. Z tagiem internetowym:Powyższe powinno całkowicie wyjaśnić wszystkie komentarze @Bob 3. Parafrazowanie:
.*
jest chciwy.*?
nie jest.pytania
Jakie są różnice w użytkowaniu. ? vs. . ?
.*?
jest poprawne tylko w składni PCRE..*
jest bardziej przenośny.[^a]*
Które jest lepsze i w jakich okolicznościach? Proszę podać przykłady.
Lepszy? To zależy od celu. Nie ma nic lepszego, każdy jest przydatny do różnych celów. Podałem kilka przykładów powyżej. Potrzebujesz więcej?
źródło