Dopasowywanie łańcucha ze stałą liczbą znaków za pomocą grep

9

Próbuję znaleźć wszystkie 6słowa literowe za pomocą grep. Obecnie mam to:

grep "^.\{6\}$" myfile.txt 

Jednak stwierdzam, że otrzymuję również wyniki, takie jak: étuis, étude.

Podejrzewam, że ma to coś wspólnego z symbolami powyżej epowyższych słów.

Czy mogę coś zrobić, aby tak się nie stało?

Dzięki za pomoc!


źródło

Odpowiedzi:

4

grepIdea postaci zależy od regionu . Jeśli znajdujesz się w ustawieniach regionalnych innych niż Unicode i grepujesz z pliku zawierającego znaki Unicode, liczba znaków nie będzie zgodna. Jeśli tak echo $LANG, zobaczysz lokalizację, w której się znajdujesz.

Jeśli ustawisz zmienne środowiskowe LC_CTYPEi / lub LANGśrodowiskowe na wartość kończącą się na „.UTF-8”, uzyskasz właściwe zachowanie:

$ cat data
étuis
letter
éééééé
$ LANG=C grep -E '^.{6}$' data
étuis
letter
$ LANG=en_US.UTF_8 grep -E '^.{6}$' data
letter
éééééé
$

Możesz zmienić ustawienia regionalne dla pojedynczego polecenia, przypisując zmienną do tego samego wiersza, co polecenie.

W tej konfiguracji znaki wielobajtowe są traktowane jako pojedyncze znaki. Jeśli chcesz całkowicie wykluczyć znaki spoza ASCII, niektóre inne odpowiedzi mają dla Ciebie odpowiednie rozwiązania.


Zauważ, że nadal możliwe jest, że coś się zepsuje, a przynajmniej nie zrobi dokładnie tego, czego oczekujesz, w obecności połączonych postaci . Twój grepmoże traktować Łacińska mała litera E + łącząc CHARACTER ostrego powyżej odmiennie niż Łacińska mała litera E z ostrą.

Michael Homer
źródło
jeśli użyjesz ., coś podobnego wăsd'sbędzie pasować
cuonglm
'jest znakiem, który może być rozsądnie częścią „łańcucha ze stałą liczbą znaków”.
Michael Homer
Może. I powinieneś ustawić oba, LC_CTYPEa LANGcoś takiego LC_CTYPE=en_US.UTF-8 LANG=en_USzawiedzie. Użyj LC_ALLdla bezpieczeństwa.
cuonglm
2

Spróbuj tego:

LC_ALL=C.UTF-8 grep -x '[_[:alnum:]]\{6\}' file

-xsłuży do dopasowania całej linii i zdefiniowanej przez POSIX (patrz grep ).

Zobacz tutaj dobre wyjaśnienie tego, co LC_ALLrobi. Możesz ustawić LANGlub LC_CTYPEużyć utf-8, aby uzyskać takie samo zachowanie. Wpływ na przyjmowanie zamówień jest LC_ALL=> LANG=> LC_CTYPE.

Cuonglm
źródło
2

Z GNU, grepgdy jest zbudowany z obsługą PCRE, możesz:

grep -Px '\X{6}'

Podczas gdy .pasuje do znaku, \Xpasuje do ideogramu / wykresu.

W lokalizacji UTF-8:

$ locale charmap
UTF-8
$ printf '\u00e9tuis\n\u00e9tudes\n' | grep -Px '\X{6}'
études
$ printf 'e\u0301tuis\ne\u0301tudes\n' | grep -Px '\X{6}'
études

W tym ostatnim étudesjest 7 znaków, 8 bajtów i 6 grafemów.

Stéphane Chazelas
źródło
Wydaje się, nie działa: echo épée | grep -Px '\X{6}'ouputépée
cuonglm
@Gnouc, musisz uruchomić to w ustawieniach regionalnych UTF-8 (jeśli épowyższe zostały zakodowane w UTF-8).
Stéphane Chazelas
Och, moje błędy. Działa z UTF-8.
cuonglm
0

Możesz spróbować czegoś takiego:

grep "^[A-Za-z]\{6\}$" myfile.txt

lub jeśli słowa mogą również zawierać liczby, wówczas:

grep "^[A-Za-z0-9]\{6\}$" myfile.txt

Po prostu dodaj do nawiasów kwadratowych dowolne znaki oprócz nich.

Warwick
źródło
To w ogóle nie będzie pasować étude, ponieważ znak ASCII odpowiadający akcentowi zepsuje regex.
Alex