Mam kilka bardzo dużych plików XML i próbuję znaleźć wiersze zawierające znaki spoza ASCII. Próbowałem następujące:
grep -e "[\x{00FF}-\x{FFFF}]" file.xml
Ale to zwraca każdą linię w pliku, niezależnie od tego, czy linia zawiera znak z określonego zakresu.
Czy mam niewłaściwą składnię, czy robię coś innego źle? Próbowałem też:
egrep "[\x{00FF}-\x{FFFF}]" file.xml
(z pojedynczymi i podwójnymi cudzysłowami otaczającymi wzór).
Odpowiedzi:
Możesz użyć polecenia:
To da ci numer linii i podświetli na czerwono znaki inne niż ascii.
W niektórych systemach, w zależności od ustawień, powyższe nie będzie działać, więc możesz grep odwrotnie
Zauważ też, że ważnym bitem jest
-P
flaga, która jest równa--perl-regexp
: więc zinterpretuje twój wzór jako wyrażenie regularne Perla. Mówi to równieżźródło
grep
(w OS X 10.8 Mountain Lion), ponieważ nie obsługuje tejP
opcji.grep
jest dostępna wdupes
bibliotece Homebrew (włącz używaniebrew tap homebrew/dupes
):brew install grep
dupes
biblioteki jest instalacjapcre
zamiast:brew install pcre
... w ramach tego otrzymaszpcregrep
narzędzie, którego możesz użyć w następujący sposób:pcregrep --color='auto' -n "[\x80-\xFF]" file.xml
brew
Użytkownicy komputerów Mac mogą zainstalować jądra GNUbrew install coreutils
. To da ci wiele narzędzi GNU z prefiksem „g” - w tym przypadku użyjggrep
. Powinno to uniknąć problemów wynikających z wymiany narzędzia systemowego, ponieważ specyficzne dla systemu skrypty Mac zależą teraz od grep BSD.ag "[\x80-\xFF]" file
the_silver_searcher
Zamiast przyjmować założenia dotyczące zakresu bajtów znaków spoza ASCII, podobnie jak większość powyższych rozwiązań, nieco lepiej IMO wyraźnie określa rzeczywisty zakres bajtów znaków ASCII.
Tak więc pierwszym rozwiązaniem byłoby na przykład:
(który w zasadzie greps dla dowolnego znaku spoza zakresu szesnastkowego ASCII: od \ x00 do \ x7F)
Na Mountain Lion, który nie będzie działał (z powodu braku obsługi PCRE w BSD grep) , ale z
pcre
zainstalowanym przez Homebrew, będą działały równie dobrze:Jakieś zalety lub wady, o których każdy może pomyśleć?
źródło
LC_COLLATE=C grep $'[^\1-\177]'
działa (dla plików bez bajtów zerowych)Poniższe działa dla mnie:
Znaki inne niż ASCII zaczynają się od 0x80 i przechodzą do 0xFF, patrząc na bajty. Grep (i rodzina) nie przetwarzają Unicode, aby scalić znaki wielobajtowe w jedną całość w celu dopasowania wyrażenia regularnego, jak się wydaje.
-P
Opcja w moim grep umożliwia korzystanie z\xdd
ucieczek z klas znakowych aby osiągnąć to, co chcesz.źródło
echo '소녀시대' | grep -P "[\x80-\xFF]"
nic mi nie zwraca - czy ktoś może to potwierdzić? (GNU grep 2.21)echo '소녀시대' | grep -P "[^\x00-\x7F]"
. Lub po prostu użyj,the_silver_searcher
jak wskazał @slf:echo '소녀시대' | ag "[\x80-\xFF]"
W perl
źródło
perl -lne 'print if /[^[:ascii:]]/' file.xml
Prostym sposobem jest zdefiniowanie znaku spoza ASCII ... jako znaku, który nie jest znakiem ASCII.
Dodaj kartę po
^
razie potrzeby.Ustawienie
LC_COLLATE=C
pozwala uniknąć przykrych niespodzianek dotyczących znaczenia zakresów postaci w wielu lokalizacjach. UstawienieLC_CTYPE=C
jest konieczne, aby dopasować znaki jednobajtowe - w przeciwnym razie w poleceniu pominięte zostaną nieprawidłowe sekwencje bajtów w bieżącym kodowaniu. UstawienieLC_ALL=C
całkowicie eliminuje efekty zależne od lokalizacji.źródło
echo "A" | LC_COLLATE=C grep '[^ -~]'
zwraca meczLC_ALL=en_US.UTF-8
, to przebijaLC_COLLATE
ustawienie. Nie powinieneś mieć tego w swoim środowisku!LC_ALL
polega tylko na wymuszeniu określonego zadania, aby użyć określonego ustawienia narodowego, zwykleC
. Aby ustawić domyślne ustawienia regionalne dla wszystkich kategorii, ustawLANG
.LC_ALL=C
, że działa inaczej w Mac OS X i Ubuntu. Po dodaniu tego ustawienia dają ten sam wynik.Oto inny wariant, który znalazłem, który dał zupełnie inne wyniki niż wyszukiwanie grep
[\x80-\xFF]
w zaakceptowanej odpowiedzi. Być może przyda się ktoś, kto znajdzie dodatkowe postacie inne niż ascii:grep --color='auto' -P -n "[^[:ascii:]]" myfile.txt
Uwaga: grep mojego komputera (Mac) nie miał
-P
opcji, więc zrobiłembrew install grep
i rozpocząłem powyższe połączenie zggrep
zamiastgrep
.źródło
Działa następujący kod:
Zamień
/tmp
na nazwę katalogu, który chcesz przeszukać.źródło
Wyszukiwanie znaków niedrukowalnych. TLDR; Streszczenie
LC_ALL=C
potrzebne, aby grep działał zgodnie z oczekiwaniami z rozszerzonym UnicodeSO preferowane wyszukiwarki znaków innych niż ascii:
jak w górnej odpowiedzi, odwrotne grep:
jak w górnej odpowiedzi, ale Z
LC_ALL=C
:. . więcej . . dręczące szczegóły na ten temat:. . .
Zgadzam się z Harveyem powyżej ukrytym w komentarzach, często bardziej przydatne jest wyszukiwanie znaków niedrukowalnych LUB łatwo jest myśleć bez ASCII, kiedy naprawdę powinieneś myśleć o drukowaniu. Harvey sugeruje „użyj tego:”
[^\n -~]
”. Dodaj \ r dla plików tekstowych DOS. To tłumaczy się na„[^\x0A\x020-\x07E]
”i dodaje \ x0D dla CR”Ponadto dodanie -c (pokaż liczbę dopasowanych wzorców) do grep jest przydatne podczas wyszukiwania znaków niedrukowalnych, ponieważ dopasowane łańcuchy mogą zepsuć terminal.
Odkryłem, że dodanie zakresu 0-8 i 0x0e-0x1f (do zakresu 0x80-0xff) jest użytecznym wzorcem. Wyklucza to TAB, CR i LF oraz jeden lub dwa inne nietypowe znaki drukowalne. Więc IMHO jest dość przydatnym (choć surowym) wzorem grepa:
AKTUALNIE, ogólnie rzecz biorąc, musisz to zrobić:
awaria:
Np. Praktyczny przykład użycia find do grepowania wszystkich plików w bieżącym katalogu:
Czasami możesz chcieć dostosować grep. np. znak BS (0x08 - backspace) używany w niektórych plikach do wydruku lub w celu wykluczenia VT (0x0B - tabulator pionowy). Znaki BEL (0x07) i ESC (0x1B) można również uznać za drukowalne w niektórych przypadkach.
AKTUALIZACJA: Musiałem ostatnio to ponownie odwiedzić. I YYMV w zależności od ustawień terminala / słonecznej prognozy pogody ALE. . Zauważyłem, że grep nie znalazł wielu znaków Unicode lub Extended. Mimo że intuicyjnie powinny pasować do zakresu od 0x80 do 0xff, 3 i 4 bajtowe znaki Unicode nie zostały dopasowane. ??? Czy ktoś może to wyjaśnić? TAK. @frabjous zapytał, a @calandoa wyjaśnił, że
LC_ALL=C
należy użyć, aby ustawić ustawienia regionalne dla polecenia, aby dopasować grep.np. moja lokalizacja jest
LC_ALL=
pustagrep z
LC_ALL=
pustymi dopasowaniami 2-bajtowe znaki zakodowane, ale nie zakodowane 3 i 4 bajty:grep z
LC_ALL=C
wydaje się pasować do wszystkich rozszerzonych znaków, które chciałbyś:TO dopasowanie perla (częściowo znalezione gdzie indziej przy przepływie stosu) LUB odwrotne grep na górnej odpowiedzi NIE wydają się znajdować WSZYSTKICH ~ dziwnych ~ i ~ cudownych ~ "nie-ascii" znaków bez ustawiania ustawień regionalnych:
SO preferowane wyszukiwarki znaków innych niż ascii:
jak w górnej odpowiedzi, odwrotne grep:
jak w górnej odpowiedzi, ale Z
LC_ALL=C
:źródło
O dziwo, musiałem to dziś zrobić! Skończyło się na użyciu Perla, ponieważ nie mogłem zmusić grep / egrep do pracy (nawet w trybie -P). Coś jak:
W przypadku znaków Unicode (jak
\u2212
w przykładzie poniżej) użyj tego:źródło
Interesujące może być sprawdzenie, jak wyszukać jedną postać Unicode. To polecenie może pomóc. Musisz tylko znać kod w UTF8
źródło
Znalezienie wszystkich znaków innych niż ascii sprawia wrażenie, że albo szuka się ciągów Unicode, albo zamierza usunąć te znaki indywidualnie.
W przypadku tych pierwszych wypróbuj jedną z nich (zmienna
file
służy do automatyzacji):Waniliowe grep nie działa poprawnie bez LC_ALL = C, jak wspomniano w poprzednich odpowiedziach.
Zakres ASCII to
x00-x7F
spacjax20
, ponieważ ponieważ łańcuchy mają spacje, zakres ujemny pomija je.Zakres inny niż ASCII jest taki
x80-xFF
, że ponieważ ciągi znaków mają spacje, zakres dodatni dodaje je.Zakłada się, że ciąg znaków składa się z co najmniej 7 kolejnych znaków w zakresie.
{7,}
.Dla danych wyjściowych odczytywanych przez powłokę
uchardet $file
zwraca domysły kodowania pliku, które jest przekazywane do iconv w celu automatycznej interpolacji.źródło
uchardet
poleceniu. Dzięki za heads-up!