429 Stimmen

Wie kann ich nach allen Nicht-ASCII-Zeichen fahnden?

Ich habe mehrere sehr große XML-Dateien, und ich versuche, die Zeilen zu finden, die Nicht-ASCII-Zeichen enthalten. Ich habe das Folgende versucht:

grep -e "[\x{00FF}-\x{FFFF}]" file.xml

Dies gibt jedoch jede Zeile in der Datei zurück, unabhängig davon, ob die Zeile ein Zeichen in dem angegebenen Bereich enthält.

Habe ich die Syntax falsch oder mache ich etwas anderes falsch? Ich habe es auch versucht:

egrep "[\x{00FF}-\x{FFFF}]" file.xml 

(wobei das Muster sowohl in einfachen als auch in doppelten Anführungszeichen steht).

30voto

ryanm Punkte 2213

Hier ist eine weitere Variante, die ich gefunden habe vollständig verschiedene Ergebnisse der grep-Suche nach [\x80-\xFF] in der akzeptierten Antwort. Vielleicht wird es für jemanden nützlich sein, weitere Nicht-ASCI-Zeichen zu finden:

grep --color='auto' -P -n "[^[:ascii:]]" myfile.txt

Anmerkung: Das grep meines Computers (ein Mac) hat keine -P Option, also habe ich brew install grep und startete den obigen Aufruf mit ggrep anstelle von grep .

22voto

gaoithe Punkte 3817

Suche nach nicht druckbaren Zeichen. TLDR; Zusammenfassung

  1. Suche nach Steuerzeichen UND erweitertem Unicode
  2. Einstellung des Gebietsschemas, z. B. LC_ALL=C benötigt, damit grep das tut, was man bei erweitertem Unicode erwarten kann

SO die bevorzugten nicht-ascii Zeichenfinder:

$ perl -ne 'print "$. $_" if m/[\x00-\x08\x0E-\x1F\x80-\xFF]/' notes_unicode_emoji_test

wie in der oberen Antwort, dem inversen grep:

$ grep --color='auto' -P -n "[^\x00-\x7F]" notes_unicode_emoji_test

wie in der oberen Antwort, aber MIT LC_ALL=C :

$ LC_ALL=C grep --color='auto' -P -n "[\x80-\xFF]" notes_unicode_emoji_test

. . mehr . . unerträgliche Details dazu: .

Ich stimme zu mit Harvey oben in den Kommentaren vergraben, ist es oft nützlicher, nach nicht druckbaren Zeichen zu suchen ODER man denkt leicht an nicht-ASCII, wenn man eigentlich an nicht druckbar denken sollte. Harvey schlägt vor, "dies zu verwenden: " [^\n -~] ". hinzufügen. \r für DOS-Textdateien. Das heißt übersetzt: " [^\x0A\x020-\x07E] " und fügen Sie hinzu \x0D für CR"

Auch das Hinzufügen von -c (show count of patterns matched) zu grep ist nützlich, wenn man nach nicht druckbaren Zeichen sucht, da die gefundenen Zeichenfolgen das Terminal durcheinander bringen können.

Ich habe festgestellt, dass das Hinzufügen der Bereiche 0-8 und 0x0e-0x1f (zum Bereich 0x80-0xff) ein nützliches Muster ist. Dies schließt TAB, CR und LF sowie ein oder zwei weitere seltene druckbare Zeichen aus. Also IMHO ein Ein recht nützliches (wenn auch grobes) grep-Muster ist DIESES:

grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" *

TATSÄCHLICH müssen Sie dies im Allgemeinen tun:

LC_ALL=C grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" *

Panne:

LC_ALL=C - set locale to C, otherwise many extended chars will not match (even though they look like they are encoded > 0x80)
\x00-\x08 - non-printable control chars 0 - 7 decimal
\x0E-\x1F - more non-printable control chars 14 - 31 decimal
\x80-1xFF - non-printable chars > 128 decimal
-c - print count of matching lines instead of lines
-P - perl style regexps

Instead of -c you may prefer to use -n (and optionally -b) or -l
-n, --line-number
-b, --byte-offset
-l, --files-with-matches

Z.B. ein praktisches Beispiel für die Verwendung von find, um alle Dateien im aktuellen Verzeichnis zu durchsuchen:

LC_ALL=C find . -type f -exec grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" {} + 

Möglicherweise möchten Sie den Grep manchmal anpassen. z.B. BS(0x08 - backspace) Zeichen, das in einigen druckbaren Dateien verwendet wird, oder VT(0x0B - vertical tab) ausschließen. Auch die Zeichen BEL(0x07) und ESC(0x1B) können in einigen Fällen als druckbar angesehen werden.

Non-Printable ASCII Chars
** marks PRINTABLE but CONTROL chars that is useful to exclude sometimes
Dec   Hex Ctrl Char description           Dec Hex Ctrl Char description
0     00  ^@  NULL                        16  10  ^P  DATA LINK ESCAPE (DLE)
1     01  ^A  START OF HEADING (SOH)      17  11  ^Q  DEVICE CONTROL 1 (DC1)
2     02  ^B  START OF TEXT (STX)         18  12  ^R  DEVICE CONTROL 2 (DC2)
3     03  ^C  END OF TEXT (ETX)           19  13  ^S  DEVICE CONTROL 3 (DC3)
4     04  ^D  END OF TRANSMISSION (EOT)   20  14  ^T  DEVICE CONTROL 4 (DC4)
5     05  ^E  END OF QUERY (ENQ)          21  15  ^U  NEGATIVE ACKNOWLEDGEMENT (NAK)
6     06  ^F  ACKNOWLEDGE (ACK)           22  16  ^V  SYNCHRONIZE (SYN)
7     07  ^G  BEEP (BEL)                  23  17  ^W  END OF TRANSMISSION BLOCK (ETB)
8     08  ^H  BACKSPACE (BS)**            24  18  ^X  CANCEL (CAN)
9     09  ^I  HORIZONTAL TAB (HT)**       25  19  ^Y  END OF MEDIUM (EM)
10    0A  ^J  LINE FEED (LF)**            26  1A  ^Z  SUBSTITUTE (SUB)
11    0B  ^K  VERTICAL TAB (VT)**         27  1B  ^[  ESCAPE (ESC)
12    0C  ^L  FF (FORM FEED)**            28  1C  ^\  FILE SEPARATOR (FS) RIGHT ARROW
13    0D  ^M  CR (CARRIAGE RETURN)**      29  1D  ^]  GROUP SEPARATOR (GS) LEFT ARROW
14    0E  ^N  SO (SHIFT OUT)              30  1E  ^^  RECORD SEPARATOR (RS) UP ARROW
15    0F  ^O  SI (SHIFT IN)               31  1F  ^_  UNIT SEPARATOR (US) DOWN ARROW

UPDATE: Das musste ich kürzlich wiederholen. Und, YYMV je nach Terminaleinstellungen/Sonnenwettervorhersage, ABER . Ich habe festgestellt, dass grep fand nicht viele Unicode- oder erweiterte Zeichen. Obwohl sie intuitiv in den Bereich 0x80 bis 0xff passen sollten, wurden 3- und 4-Byte-Unicode-Zeichen nicht gefunden. ??? Kann mir das jemand erklären? YES. @frabjous fragte und @calandoa erklärte das LC_ALL=C sollte verwendet werden, um die Locale für den Befehl zu setzen, damit grep passt.

z.B. mein Gebietsschema LC_ALL= leer

$ locale
LANG=en_IE.UTF-8
LC_CTYPE="en_IE.UTF-8"
.
.
LC_ALL=

grep mit LC_ALL= empty passt auf 2-Byte-kodierte Zeichen, aber nicht auf 3 und 4-Byte-kodierte:

$ grep -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" notes_unicode_emoji_test
5:© copyright c2a9
7:call  underscore c2a0
9:CTRL
31:5 © copyright
32:7 call  underscore

grep mit LC_ALL=C scheint mit allen gewünschten erweiterten Zeichen übereinzustimmen:

$ LC_ALL=C grep --color='auto' -P -n "[\x80-\xFF]" notes_unicode_emoji_test  
1: unicode dashes e28090
3: Heart With Arrow Emoji - Emojipedia == UTF8? f09f9298
5: copyright c2a9
7:call underscore c2a0
11:LIVEE!          YEOW, mix of japanese and chars from other e38182 e38184 . . e0a487
29:1  unicode dashes
30:3  Heart With Arrow Emoji - Emojipedia == UTF8 e28090
31:5  copyright
32:7 call underscore
33:11 LIVEE!          YEOW, mix of japanese and chars from other
34:52 LIVEE!          YEOW, mix of japanese and chars from other
81:LIVEE!          YEOW, mix of japanese and chars from other

DIESES Perl-Match (teilweise an anderer Stelle auf Stackoverflow gefunden) ODER das inverse grep auf der oberen Antwort scheinen ALLE ~weird~ und ~wonderful~ "non-ascii"-Zeichen zu finden, ohne Locale zu setzen:

$ grep --color='auto' -P -n "[^\x00-\x7F]" notes_unicode_emoji_test

$ perl -ne 'print "$. $_" if m/[\x00-\x08\x0E-\x1F\x80-\xFF]/' notes_unicode_emoji_test  

1  unicode dashes e28090
3  Heart With Arrow Emoji - Emojipedia == UTF8? f09f9298
5 © copyright c2a9
7 call  underscore c2a0
9 CTRL-H CHARS URK URK URK 
11 LIVEE!          YEOW, mix of japanese and chars from other e38182 e38184 . . e0a487
29 1  unicode dashes
30 3  Heart With Arrow Emoji - Emojipedia == UTF8 e28090
31 5 © copyright
32 7 call  underscore
33 11 LIVEE!          YEOW, mix of japanese and chars from other
34 52 LIVEE!          YEOW, mix of japanese and chars from other
73 LIVEE!          YEOW, mix of japanese and chars from other

SO die bevorzugten nicht-ascii Zeichenfinder:

$ perl -ne 'print "$. $_" if m/[\x00-\x08\x0E-\x1F\x80-\xFF]/' notes_unicode_emoji_test

wie in der oberen Antwort, dem inversen grep:

$ grep --color='auto' -P -n "[^\x00-\x7F]" notes_unicode_emoji_test

wie in der oberen Antwort, aber MIT LC_ALL=C :

$ LC_ALL=C grep --color='auto' -P -n "[\x80-\xFF]" notes_unicode_emoji_test

10voto

user7417071 Punkte 91

Der folgende Code funktioniert:

find /tmp | perl -ne 'print if /[^[:ascii:]]/'

Ersetzen Sie /tmp mit dem Namen des Verzeichnisses, das Sie durchsuchen möchten.

2voto

Kajukenbo Punkte 59

Diese Methode sollte mit jeder POSIX-kompatiblen Version von awk y iconv . Wir können die Vorteile nutzen file y tr auch.

curl じゃない POSIX natürlich.

Die oben genannten Lösungen mögen in einigen Fällen besser sein, aber sie scheinen von GNU/Linux-Implementierungen oder zusätzlichen Tools abzuhängen.

Erhalten Sie eine Beispieldatei:

$ curl -Ls http://gutenberg.org/files/84/84-0.txt

$ file 84-0.txt

84-0.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators

Suche nach UTF-8-Zeichen:

$ awk '/[\x80-\xFF]/ { print }' 84-0.txt

oder nicht-ASCII

$ awk '/[^[:ascii:]]/ { print }' 84-0.txt

Konvertiert UTF-8 in ASCII und entfernt problematische Zeichen:

$ iconv -c -t ASCII 84-0.txt > 84-ascii.txt

Prüfen Sie es:

$ file 84-ascii.txt

84-ascii.txt: ASCII text, with CRLF line terminators

Verbessern Sie es:

$ tr -d '\015' < 84-ascii.txt | file -

/dev/stdin: ASCII text

YMMV

1voto

dty Punkte 18552

Seltsamerweise musste ich das heute tun! Am Ende habe ich Perl benutzt, weil ich grep/egrep nicht zum Laufen bringen konnte (selbst im -P-Modus). Etwas wie:

cat blah | perl -en '/\xCA\xFE\xBA\xBE/ && print "found"'

Für Unicode-Zeichen (wie \u2212 im Beispiel unten) verwenden:

find . ... -exec perl -CA -e '$ARGV = @ARGV[0]; open IN, $ARGV; binmode(IN, ":utf8"); binmode(STDOUT, ":utf8"); while (<IN>) { next unless /\N{U+2212}/; print "$ARGV: $&: $_"; exit }' '{}' \;

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X