Jak używać [\ w] + w wyrażeniu regularnym w sed?

24

Korzystam z systemu Windows, ale wydaje mi się, że moje pytanie jest nadal słusznie umieszczone tutaj.

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

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

Zauważyłem, że następujące prace (wyjście here):

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

Ale to nie działa (nic nie wyprowadza):

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

To znowu robi (wysyłanie here):

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

Więc [\w]jest coś konkretnego do wyrażeń regularnych Perl, zakładam. Czy to jest poprawne?

Porozmawiajmy sed. To działa (wysyłanie gone):

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

I znowu to nie (wyjście here):

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

Jak mogę aktywować wyrażenia regularne Perla dla sed - czy jest jakiś sposób?

bers
źródło

Odpowiedzi:

11

Różne narzędzia i ich wersje obsługują różne warianty wyrażeń regularnych. Dokumentacja każdego powie ci, co obsługuje.

Istnieją standardy, dzięki którym można polegać na minimalnym zestawie funkcji, które są dostępne we wszystkich zgodnych aplikacjach.

Na przykład wszystkie współczesne implementacje sedi grepimplementacje podstawowych wyrażeń regularnych określonych przez POSIX (co najmniej jedna wersja standardu, ale ten standard nie ewoluował pod tym względem wiele w ciągu ostatnich kilku dekad).

W POSIX BRE i ERE masz [:alnum:]klasę znaków. To pasuje do liter i cyfr w twoim języku (pamiętaj, że często zawiera o wiele więcej niż a-zA-Z0-9chyba, że ​​język to C).

Więc:

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

pasuje do jednej lub więcej alnums lub _.

[\w]jest wymagany przez POSIX, aby pasował do ukośnika odwrotnego lub w. Więc nie będzie znaleźć greplub sedwdrożenie gdzie to jest dostępne (chyba poprzez niestandardowe opcje).

Zachowanie dla \wsamego nie jest określone przez POSIX, więc implementacje mogą robić to, co chcą. GNU grepdodało to dawno temu.

GNU grepkiedyś posiadało własny silnik wyrażenia regularnego, jednak teraz używa silnika GNU libc (choć osadza własną kopię).

Ma to na celu dopasowanie alnumów i podkreślników w Twoim regionie. Jednak obecnie ma błąd polegający na tym, że dopasowuje tylko znaki jednobajtowe (na przykład nie é w ustawieniach regionalnych UTF-8, nawet jeśli jest to wyraźnie litera i mimo że pasuje do é we wszystkich lokalizacjach, w których é jest pojedynczym postać).

Istnieje również \woperator wyrażeń regularnych w wyrażeniach regularnych Perla i PCRE. PCRE / perl nie są wyrażeniami regularnymi POSIX, to po prostu kolejna rzecz.

Teraz, gdy GNU grep -Pużywa PCRE, ma ten sam problem, co bez niego -P. Można go jednak obejść, używając (*UCP)(chociaż ma to również skutki uboczne w lokalizacjach innych niż UTF8).

GNU sedużywa także wyrażeń regularnych GNU libc do własnych wyrażeń regularnych. Używa go w taki sposób, że nie ma tego samego błędu co GNU grep.

GNU sednie obsługuje PCRE. Kod zawiera pewne dowody, że próbowano go już wcześniej, ale wydaje się, że nie jest już w porządku obrad.

Jeśli chcesz mieć wyrażenia regularne Perla, po prostu użyj perl.

W przeciwnym razie powiedziałbym, że zamiast próbować polegać na fałszywej niestandardowej funkcji twojej konkretnej implementacji sed/ grep, lepiej trzymać się standardu i używać [_[:alnum:]].

Stéphane Chazelas
źródło
[_[:alnum:]]Jest to miłe obejście, które pozwala mi przedłużyć go tak jak [\w/]( [_[:alnum:]/]w tym przypadku).
włókien
1
Ta odpowiedź jest obecnie nieaktualna w odniesieniu do ograniczeń GNU grep.
Stéphane Chazelas
7

Masz rację - \wjest częścią wyrażeń regularnych kompatybilnych z PCRE. Nie jest to jednak część „standardowego” wyrażenia regularnego. http://www.regular-expressions.info/posix.html

Niektóre wersje sedmogą go wspierać, ale sugeruję najprostszym sposobem jest po prostu użyć perlw sedtrybie określając -pflagę. (Wraz z -e). (Więcej szczegółów w perlrun)

Ale nie potrzebujesz []tego w tym przykładzie - dotyczy to grup ważnych rzeczy.

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

Lub w systemie Windows:

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

Zobacz perlrewięcej materiałów PCRE.

Możesz pobrać perl tutaj: http://www.activestate.com/activeperl/downloads

Sobrique
źródło
Proszę zwrócić uwagę na różnicę pomiędzy \wi [\w]na moje pytanie. Zaktualizuję go o dane wyjściowe każdego polecenia, aby wyjaśnić, które z nich działa, a które nie. W szczególności sedrozumie \w, ale nie [\w]. Ponadto muszę [\w]pracować, ponieważ chcę [\w/]na przykład używać .
włókien
W takim przypadku jest to prawdopodobnie problem cytowania. Tak czy inaczej - perlmożna to zrobić :).
Sobrique
Dzięki! Odpowiedź Stéphane'a Chazelasa jest nieco bliższa temu, o co prosiłem (skoro nie mam zainstalowanego Perla - chyba użytkownika Windowsa du * b), więc zaakceptowałem jego odpowiedź.
włókien
W porządku - ale polecam zainstalowanie Perla w systemie Windows. To jedna z pierwszych rzeczy, które mnie dotyczą, i uważam to za niezwykle pomocne.
Sobrique,
\wbył w GNU grep (w latach 80.) zanim był w perlu, a w GNU emacs prawdopodobnie nawet wcześniej.
Stéphane Chazelas
1

Podejrzewam, że grepi sedinaczej decyduję, kiedy zastosować, []a kiedy rozwinąć \w. W perl regex \woznacza dowolny znak słowa i []zdefiniuj grupę, aby zastosować dowolny ze znaków jako dopasowanie. Jeśli „rozszerzysz” \wpoprzednią [], będzie to klasa znaków wszystkich znaków słownych. Jeśli zamiast tego zrobisz []najpierw, będziesz mieć klasę znaków z dwoma znakami, \a wwięc będzie pasować do dowolnego wzoru zawierającego jeden lub więcej z tych dwóch znaków.

Tak więc wydaje się, że sedjest widząc []i traktując ją jako zawierającą dokładnie dopasować znaki zamiast cześć specjalną sekwencję \w, jak perli grepzrobić. Oczywiście, []w tym przykładzie są całkowicie niepotrzebne, ale można sobie wyobrazić przypadki, w których byłoby to ważne, ale wtedy można sprawić, że będzie działać z parens i ors.

Eric Renouf
źródło
Byłbym zaskoczony, gdyby tak było. \ jest kodem ucieczkowym i można go użyć do zmiany znaczenia separatorów. Z natury oznacza to, że musi mieć wyższy priorytet niż jakakolwiek inna rzecz. Myślę, że bardziej prawdopodobne jest to, że nie został zaimplementowany, ponieważ \wnie jest częścią specyfikacji wyrażeń regularnych
Sobrique
Cóż, empirycznie wydaje się, że tak jest w przypadku używania gnu sed: echo whe\\ere | sed -r 's/[\w]+/gone/gdaje mi gonehegoneereto, jakby pasowało do każdego z w ` and 'i dokonywało zamiany
Eric Renouf
Mogę potwierdzić to, co widzi Eric Renouf. Więc chcemy jakoś cofnąć odwrotny ukośnik? :)
BERS
Nie sądzę, żeby to była właściwa odpowiedź. Sed po prostu nie obsługuje mieszania różnych typów definicji klas postaci, więc odpowiedź brzmi, jeśli musisz użyć obu typów klas postaci, wybierz inne narzędzie, lub jeśli wybierasz sed, użyj składni, którą obsługuje
Eric Renouf