Widziałem ten przykład:
hello=ho02123ware38384you443d34o3434ingtod38384day
echo ${hello//[0-9]/}
Co jest zgodne z następującą składnią: ${variable//pattern/replacement}
Niestety pattern
wydaje się, że pole nie obsługuje pełnej składni wyrażenia regularnego (jeśli używam .
lub \s
, na przykład, próbuje dopasować znaki literału).
Jak mogę wyszukać / zamienić ciąg przy użyciu pełnej składni wyrażeń regularnych?
\s
nie jest częścią standardowej składni wyrażeń regularnych zdefiniowanej w POSIX (ani BRE ani ERE); jest to rozszerzenie PCRE i przeważnie niedostępne z powłoki.[[:space:]]
jest bardziej uniwersalnym odpowiednikiem.\s
można zastąpić[[:space:]]
, nawiasem mówiąc,.
przez?
, a rozszerzenia extglob do bazowego języka wzorców powłoki mogą być używane do takich rzeczy, jak opcjonalne podgrupy, grupy powtarzane i tym podobne.Odpowiedzi:
Użyj sed :
Zwróć uwagę, że kolejne
-e
są przetwarzane w kolejności. Ponadtog
flaga wyrażenia będzie pasować do wszystkich wystąpień w danych wejściowych.Możesz także wybrać swoje ulubione narzędzie używając tej metody, czyli perl, awk, np:
Może to pozwolić na bardziej kreatywne dopasowania ... Na przykład w powyższym wycinku numeryczny zamiennik nie zostanie użyty, chyba że w pierwszym wyrażeniu wystąpi dopasowanie (z powodu leniwej
and
oceny). I oczywiście masz pełne wsparcie językowe Perla, aby spełnić twoje wymagania ...źródło
sed
lub innych narzędzi zewnętrznych jest kosztowne ze względu na czas inicjalizacji procesu. Szczególnie szukałem rozwiązania all-bash, ponieważ stwierdziłem, że używanie podstawień basha jest ponad 3x szybsze niż wywoływaniesed
każdego elementu w mojej pętli.W rzeczywistości można to zrobić w czystym bashu:
... daje ...
źródło
=~
jest kluczem. Ale trochę niezgrabny, biorąc pod uwagę zmianę przypisania w pętli. Rozwiązanie @jheddings 2 lata wcześniej to kolejna dobra opcja - wywołanie sed lub perl).sed
lubperl
jest rozsądne, jeśli używasz każdego wywołania do przetwarzania więcej niż jednej linii danych wejściowych. Wywoływanie takiego narzędzia wewnątrz pętli, w przeciwieństwie do używania pętli do przetwarzania jej strumienia wyjściowego, jest ryzykowne.$match
zamiast$BASH_REMATCH
. (Możesz sprawić, by zachowywał się jak bash zsetopt bash_rematch
.)Te przykłady działają również w bash bez potrzeby używania seda:
możesz także użyć wyrażeń nawiasowych klasy znaków
wynik
@Lanaru chciał jednak wiedzieć, jeśli dobrze rozumiem pytanie, dlaczego "pełne" rozszerzenia lub rozszerzenia PCRE
\s\S\w\W\d\D
itp. Nie działają tak, jak są obsługiwane w PHP Ruby Python itp. Te rozszerzenia pochodzą z wyrażeń regularnych zgodnych z Perlem (PCRE) i może nie być kompatybilny z innymi formami wyrażeń regularnych opartych na powłoce.Te nie działają:
wyjście z usuniętymi wszystkimi znakami literału „d”
ale poniższe działa zgodnie z oczekiwaniami
wynik
Mam nadzieję, że to wyjaśnia sprawę nieco więcej, ale jeśli jeszcze nie jesteś zdezorientowany, dlaczego nie wypróbujesz tego na Mac OS X, który ma włączoną flagę REG_ENHANCED:
Na większości smaków * nix zobaczysz tylko następujące dane wyjściowe:
nJoy!
źródło
${foo//$bar/$baz}
jest składnią POSIX.2 BRE ani ERE - jest to dopasowywanie wzorców w stylu fnmatch ().${hello//[[:digit:]]/}
Works, gdybyśmy chcieli odfiltrować tylko cyfry poprzedzone literąo
,${hello//o[[:digit:]]*}
zachowywałby się zupełnie inaczej niż oczekiwano (ponieważ we wzorcach fnmatch*
dopasowuje wszystkie znaki, zamiast modyfikować pozycję bezpośrednio poprzedzającą 0 lub więcej).[0-9]
lub[[:digit:]]
Jeśli wykonujesz powtarzające się wywołania i obawiasz się wydajności, ten test pokazuje, że metoda BASH jest ~ 15x szybsza niż rozwidlanie do seda i prawdopodobnie każdego innego procesu zewnętrznego.
źródło
Użyj
[[:digit:]]
(zwróć uwagę na podwójne nawiasy) jako wzorca:Chciałem tylko podsumować odpowiedzi (zwłaszcza @ nickl- https://stackoverflow.com/a/22261334/2916086 ).
źródło