Ich habe mehrere sehr große XML-Dateien und versuche, die Zeilen zu finden, die Nicht-ASCII-Zeichen enthalten. Ich habe folgendes 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 im angegebenen Bereich enthält.
Habe ich die falsche Syntax oder mache ich etwas anderes falsch? Ich habe auch versucht:
egrep "[\x{00FF}-\x{FFFF}]" file.xml
(mit einfachen und doppelten Anführungszeichen um das Muster).
Antworten:
Sie können den folgenden Befehl verwenden:
Dies gibt Ihnen die Zeilennummer und markiert Nicht-ASCII-Zeichen in Rot.
In einigen Systemen funktioniert das oben Gesagte abhängig von Ihren Einstellungen nicht, sodass Sie nach der Umkehrung greifen können
Beachten Sie auch, dass das wichtige Bit das
-P
Flag ist, das entspricht--perl-regexp
: Es interpretiert Ihr Muster also als regulären Perl-Ausdruck. Das sagt es auchquelle
grep
(unter OS X 10.8 Mountain Lion) nicht, da dieP
Option nicht unterstützt wird .grep
in Homebrewsdupes
Bibliothek verfügbar (aktivieren mitbrew tap homebrew/dupes
):brew install grep
dupes
Bibliothek besteht darin,pcre
stattdessen Folgendes zu installieren :brew install pcre
... Als Teil davon erhalten Sie daspcregrep
Dienstprogramm, das Sie wie folgt verwenden können:pcregrep --color='auto' -n "[\x80-\xFF]" file.xml
brew
Benutzer die Coreutils von GNU mit installiert werdenbrew install coreutils
. Dadurch erhalten Sie viele GNU-Tools, denen ein 'g' vorangestellt ist - in diesem Fall verwendenggrep
. Dies sollte Probleme vermeiden, die durch das Ersetzen eines Systemdienstprogramms entstehen, da systemspezifische Mac-Skripte jetzt von BSD grep abhängen.ag "[\x80-\xFF]" file
Sie nur installieren müssenthe_silver_searcher
Anstatt Annahmen über den Bytebereich von Nicht-ASCII-Zeichen zu treffen, wie es die meisten der oben genannten Lösungen tun, ist es IMO etwas besser, stattdessen explizit über den tatsächlichen Bytebereich von ASCII-Zeichen zu sprechen.
So würde die erste Lösung zum Beispiel lauten:
(Dies gilt grundsätzlich für alle Zeichen außerhalb des hexadezimalen ASCII-Bereichs: von \ x00 bis \ x7F)
Auf Mountain Lion funktioniert dies nicht (aufgrund der fehlenden PCRE-Unterstützung in BSD grep) , aber bei
pcre
Installation über Homebrew funktioniert Folgendes genauso gut:Irgendwelche Vor- oder Nachteile, an die sich jeder denken kann?
quelle
LC_COLLATE=C grep $'[^\1-\177]'
funktioniert dies (für Dateien ohne Null-Bytes)Folgendes funktioniert für mich:
Nicht-ASCII-Zeichen beginnen bei 0x80 und gehen bei der Betrachtung von Bytes zu 0xFF. Grep (und Familie) führen keine Unicode-Verarbeitung durch, um Multibyte-Zeichen zu einer einzigen Entität zusammenzuführen, damit die Regex-Übereinstimmung Ihren Wünschen entspricht. Die
-P
Option in meinem grep ermöglicht die Verwendung von\xdd
Escapezeichen in Zeichenklassen, um das zu erreichen, was Sie wollen.quelle
echo '소녀시대' | grep -P "[\x80-\xFF]"
Gibt nichts für mich zurück - kann jemand anderes bestätigen? (GNU grep 2.21)echo '소녀시대' | grep -P "[^\x00-\x7F]"
. Oder verwenden Sie einfachthe_silver_searcher
wie von @slf angegeben:echo '소녀시대' | ag "[\x80-\xFF]"
In Perl
quelle
perl -lne 'print if /[^[:ascii:]]/' file.xml
Der einfache Weg besteht darin, ein Nicht-ASCII-Zeichen zu definieren ... als ein Zeichen, das kein ASCII-Zeichen ist.
Fügen Sie
^
bei Bedarf nach dem eine Registerkarte hinzu .Durch die Einstellung werden
LC_COLLATE=C
böse Überraschungen über die Bedeutung von Zeichenbereichen in vielen Regionen vermieden. Die EinstellungLC_CTYPE=C
ist erforderlich, um Einzelbytezeichen abzugleichen. Andernfalls würde der Befehl ungültige Bytesequenzen in der aktuellen Codierung übersehen. Durch die Einstellung werdenLC_ALL=C
länderspezifische Effekte vollständig vermieden.quelle
echo "A" | LC_COLLATE=C grep '[^ -~]'
kehrt ein Match zurückLC_ALL=en_US.UTF-8
, übertrumpft dies dieLC_COLLATE
Einstellung. Sie sollten dies nicht in Ihrer Umgebung haben!LC_ALL
besteht normalerweise nur darin, eine bestimmte Aufgabe zu zwingen, ein bestimmtes Gebietsschema zu verwendenC
. Um das Standardgebietsschema für alle Kategorien festzulegen, legen Sie festLANG
.LC_ALL=C
, es verhält sich unter Mac OS X und Ubuntu anders. Nachdem ich diese Einstellung hinzugefügt habe, erhalten sie das gleiche Ergebnis.Hier ist eine andere Variante, die ich gefunden habe und die völlig andere Ergebnisse als die Grep-Suche
[\x80-\xFF]
in der akzeptierten Antwort hervorgebracht hat. Vielleicht ist es für jemanden nützlich, zusätzliche Nicht-ASCII-Zeichen zu finden:grep --color='auto' -P -n "[^[:ascii:]]" myfile.txt
Hinweis: Der Grep meines Computers (ein Mac) hatte keine
-P
Option, daher habe ichbrew install grep
den obigen Anruf mitggrep
statt gestartetgrep
.quelle
Der folgende Code funktioniert:
Ersetzen Sie
/tmp
durch den Namen des Verzeichnisses, das Sie durchsuchen möchten.quelle
Suche nach nicht druckbaren Zeichen. TLDR; Zusammenfassung
LC_ALL=C
erforderlich, damit grep das tut, was Sie mit erweitertem Unicode erwartenSO die bevorzugten Nicht-ASCII-Zeichensucher:
wie in der oberen Antwort, die inverse grep:
wie in der oberen Antwort, aber MIT
LC_ALL=C
:. . Mehr . . qualvolles Detail dazu :. . .
Ich stimme Harvey zu, der oben in den Kommentaren vergraben ist. Oft ist es sinnvoller, nach nicht druckbaren Zeichen zu suchen, oder es ist einfach, nicht ASCII zu denken, wenn Sie wirklich nicht druckbar denken sollten.Harvey schlägt "use this:"
[^\n -~]
"vor. Fügen Sie \ r für DOS-Textdateien hinzu. Das bedeutet"[^\x0A\x020-\x07E]
"und fügen Sie \ x0D für CR" hinzu.Außerdem ist das Hinzufügen von -c (Anzahl der übereinstimmenden Muster anzeigen) zu grep hilfreich, wenn nach nicht druckbaren Zeichen gesucht wird, da die übereinstimmenden Zeichenfolgen das Terminal durcheinander bringen können.
Ich fand, 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 ungewöhnliche druckbare Zeichen aus. Meiner Meinung nach ist DIESES ein ziemlich nützliches (wenn auch grobes) Grep-Muster:
TATSÄCHLICH müssen Sie im Allgemeinen Folgendes tun:
Nervenzusammenbruch:
Beispiel: Ein praktisches Anwendungsbeispiel zum Suchen aller Dateien im aktuellen Verzeichnis:
Möglicherweise möchten Sie den Grep manchmal anpassen. zB BS-Zeichen (0x08 - Rücktaste), das in einigen druckbaren Dateien verwendet wird oder um VT auszuschließen (0x0B - vertikale Registerkarte). In einigen Fällen können die Zeichen BEL (0x07) und ESC (0x1B) auch als druckbar angesehen werden.
UPDATE: Ich musste dies kürzlich noch einmal überprüfen. Und YYMV abhängig von Terminaleinstellungen / Sonnenwettervorhersage ABER. . Ich bemerkte, dass grep nicht viele Unicode- oder erweiterte Zeichen fand. Obwohl sie intuitiv mit dem Bereich von 0x80 bis 0xff übereinstimmen sollten, wurden 3- und 4-Byte-Unicode-Zeichen nicht abgeglichen. ??? Kann jemand das erklären? JA. @frabjous fragte und @calandoa erklärte das
LC_ALL=C
dass das Gebietsschema für den Befehl festgelegt werden sollte, damit grep übereinstimmt.zB mein Gebietsschema
LC_ALL=
leergrep mit
LC_ALL=
leeren Übereinstimmungen 2 Byte codierte Zeichen, aber nicht 3 und 4 Byte codiert:grep with
LC_ALL=C
scheint mit allen erweiterten Zeichen übereinzustimmen , die Sie möchten:DIESES Perl-Match (teilweise an anderer Stelle im Stackoverflow zu finden) ODER das inverse Grep in der oberen Antwort scheinen ALLE ~ seltsamen ~ und ~ wunderbaren ~ "Nicht-ASCII" -Zeichen zu finden, ohne das Gebietsschema festzulegen:
SO die bevorzugten Nicht-ASCII-Zeichensucher:
wie in der oberen Antwort, die inverse grep:
wie in der oberen Antwort, aber MIT
LC_ALL=C
:quelle
Seltsamerweise musste ich das heute tun! Am Ende habe ich Perl verwendet, weil ich grep / egrep nicht zum Laufen bringen konnte (selbst im -P-Modus). Etwas wie:
\u2212
Verwenden Sie für Unicode-Zeichen (wie im folgenden Beispiel) Folgendes:quelle
Es könnte interessant sein zu wissen, wie man nach einem Unicode-Zeichen sucht. Dieser Befehl kann helfen. Sie müssen nur den Code in UTF8 kennen
quelle
Das Finden aller Nicht-ASCII-Zeichen erweckt den Eindruck, dass man entweder nach Unicode-Zeichenfolgen sucht oder beabsichtigt, diese Zeichen einzeln zu entfernen.
Versuchen Sie für erstere eine davon (Variable
file
wird für die Automatisierung verwendet):Vanilla grep funktioniert ohne LC_ALL = C nicht richtig, wie in den vorherigen Antworten angegeben.
ASCII-Bereich ist
x00-x7F
, Raum istx20
, da Zeichenfolgen Leerzeichen haben, wird es im negativen Bereich weggelassen.Nicht-ASCII-Bereich ist
x80-xFF
, da Zeichenfolgen Leerzeichen haben, wird sie durch den positiven Bereich hinzugefügt.Es wird angenommen, dass die Zeichenfolge mindestens 7 aufeinanderfolgende Zeichen innerhalb des Bereichs enthält.
{7,}
.uchardet $file
Gibt für eine Shell-lesbare Ausgabe eine Schätzung der Dateicodierung zurück, die zur automatischen Interpolation an iconv übergeben wird.quelle
uchardet
Befehls sehr nützlich . Danke für das Heads-up!