Wie finde ich Nicht-ASCII-Zeichen in MySQL?

124

Ich arbeite mit einer MySQL-Datenbank, in die einige Daten aus Excel importiert wurden . Die Daten enthalten Nicht- ASCII- Zeichen (Bindestriche usw.) sowie versteckte Zeilenumbrüche oder Zeilenvorschübe. Gibt es eine Möglichkeit, diese Datensätze mit MySQL zu finden?

Ed Mays
quelle
8
Ollie Jones hat eine viel bessere Antwort (siehe unten).
Jonathan Arkell
1
@ JonathanArkell Nicht mehr unten :)
Brilliand
Korrektur .. überprüfe die Mitte! ;)
Jonathan Arkell
Dies ist die Antwort @ Jonathan spricht über stackoverflow.com/a/11741314/792066
Braiam

Antworten:

64

Es hängt genau davon ab, was Sie als "ASCII" definieren, aber ich würde vorschlagen, eine Variante einer Abfrage wie diese zu versuchen:

SELECT * FROM tableName WHERE columnToCheck NOT REGEXP '[A-Za-z0-9]';

Diese Abfrage gibt alle Zeilen zurück, in denen columnToCheck nicht alphanumerische Zeichen enthält. Wenn Sie andere Zeichen haben, die akzeptabel sind, fügen Sie sie der Zeichenklasse im regulären Ausdruck hinzu. Wenn beispielsweise Punkte, Kommas und Bindestriche in Ordnung sind, ändern Sie die Abfrage in:

SELECT * FROM tableName WHERE columnToCheck NOT REGEXP '[A-Za-z0-9.,-]';

Die relevanteste Seite der MySQL-Dokumentation ist wahrscheinlich 12.5.2 Reguläre Ausdrücke .

Chad Birch
quelle
3
Sollten Sie nicht dem Bindestrich und der Periode entkommen? (Da sie in einem regulären Ausdruck spezielle Bedeutungen haben.) SELECT * FROM tableName WHERE NOT columnToCheck REGEXP '[A-Za-z0-9 \., \ -]';
Tooony
3
@Tooony Nein, innerhalb eines Sets bedeutet ein Punkt nur sich selbst und der Bindestrich hat nur eine besondere Bedeutung zwischen anderen Zeichen. Am Ende des Sets bedeutet es nur sich selbst.
Michael Speer
10
Diese Abfrage findet nur alle Zeilen in tableName, die kein alphanumerisches Zeichen enthalten. Dies beantwortet die Frage nicht.
Rob Bailey
8
Dies gilt für Spalten, die überhaupt keine ASCII-Zeichen enthalten. Daher fehlen Spalten mit einer Mischung aus ASCII- und Nicht-ASCII-Zeichen. Die folgende Antwort von zende sucht nach einem oder mehreren Nicht-ASCII-Zeichen. Dies hat mir größtenteils geholfenSELECT * FROM tbl WHERE colname NOT REGEXP '^[A-Za-z0-9\.,@&\(\) \-]*$';
Frank Forte
1
Dies funktioniert nur (für mich jedenfalls), um Zeichenfolgen zu finden, die KEINE dieser Zeichen enthalten. Es werden keine Zeichenfolgen gefunden, die eine Mischung aus ASCII- und Nicht-ASCII-Zeichen enthalten.
Ian
236

MySQL bietet eine umfassende Zeichensatzverwaltung, die bei solchen Problemen helfen kann.

SELECT whatever
  FROM tableName 
 WHERE columnToCheck <> CONVERT(columnToCheck USING ASCII)

Das CONVERT(col USING charset) Funktion wandelt die nicht konvertierbaren Zeichen in Ersatzzeichen um. Dann sind der konvertierte und der nicht konvertierte Text ungleich.

Weitere Informationen finden Sie hier. https://dev.mysql.com/doc/refman/8.0/en/charset-repertoire.html

Sie können anstelle von ASCII einen beliebigen Zeichensatznamen verwenden. Wenn Sie beispielsweise herausfinden möchten, welche Zeichen in Codepage 1257 (Litauisch, Lettisch, Estnisch) nicht korrekt gerendert werden, verwenden SieCONVERT(columnToCheck USING cp1257)

O. Jones
quelle
20
Dies ist eine hervorragende Lösung für dieses Problem und viel robuster.
CraigDouglas
5
Dies ist auch nützlich, um Zeichen mit Akzenten (á ä usw.) oder Zeichen zu finden, die nicht zur Codierung gehören
Glasnhost
3
viel besser als REGEXP (was für mich nicht funktioniert, um Akzente zu finden) und bietet auch einen einfachen Mechanismus, um alles wieder
Dirk Conrad Coetsee
1
Diese Antwort funktioniert wunderbar und zeigt Zeichenfolgen an, die Nicht-ASCII-Zeichen enthalten, und nicht nur Zeichenfolgen, die nur Nicht-ASCII-Zeichen enthalten. Danke dir!
Ian
2
Hervorragende Lösung!
Mad Dog Tannen
93

Sie können ASCII als alle Zeichen mit einem Dezimalwert von 0 - 127 (0x00 - 0x7F) definieren und mithilfe der folgenden Abfrage Spalten mit Nicht-ASCII-Zeichen suchen

SELECT * FROM TABLE WHERE NOT HEX(COLUMN) REGEXP '^([0-7][0-9A-F])*$';

Dies war die umfassendste Abfrage, die ich erstellen konnte.

zende
quelle
3
Beste Antwort so weit, aber es ist noch einfacher , wie folgt aus :SELECT * FROM table WHERE LENGTH( column ) != CHAR_LENGTH( column )
SuN
15
-1 Dies kann zu fehlerhaften Ergebnissen führen. Nehmen wir zum Beispiel an, man hat eine UTF-16-Spalte, die enthält 'ā'(codiert durch die Bytesequenz 0x0101) - es würde mit diesem Test als "ASCII" betrachtet: ein falsches Negativ ; In der Tat codieren einige Zeichensätze keine ASCII-Zeichen 0x00, 0x7fworaufhin diese Lösung ein falsches Positiv ergeben würde. Verlassen Sie sich nicht auf diese Antwort!
Eggyal
2
@sun: Das hilft überhaupt nicht - viele Zeichensätze haben eine feste Länge und sind daher unabhängig vom Wert LENGTH(column)ein konstantes Vielfaches von CHAR_LENGTH(column).
Eggyal
49

Dies ist wahrscheinlich das, wonach Sie suchen:

select * from TABLE where COLUMN regexp '[^ -~]';

Es sollte alle Zeilen zurückgeben, in denen COLUMN Nicht-ASCII-Zeichen (oder nicht druckbare ASCII-Zeichen wie Zeilenumbrüche) enthält.

Peter Mortensen
quelle
7
Funktioniert super für mich. "regexp '[^ - ~]'" bedeutet, dass ein Zeichen vor dem Leerzeichen "" oder nach "~" oder ASCII 32 - 126 steht. Alle Buchstaben, Zahlen und Symbole, aber keine nicht druckbaren Dinge.
Josh
Sie können es sogar als T-Shirt bekommen;) catonmat.net/blog/my-favorite-regex
SamGoody
1
Beachten Sie die Warnung in der Dokumentation : " Die Operatoren REGEXPund RLIKEarbeiten byteweise, sind also nicht mehrbytesicher und können mit Mehrbyte-Zeichensätzen zu unerwarteten Ergebnissen führen. Außerdem vergleichen diese Operatoren die Zeichen anhand ihrer Bytewerte und Zeichen mit Akzent werden möglicherweise nicht als gleich verglichen, selbst wenn eine bestimmte Zusammenstellung sie als gleich behandelt. "
eggyal
1
Danke dafür. Was ich mich frage, ist, wie man ein Ersatzzeichen ersetzt - zB
Mars-o
1
@ mars-o - Der schwarze Diamant zeigt ein ungültiges utf8-Zeichen an. Weitere Diskussion hier
Rick James
14

Ein fehlendes Zeichen in allen obigen Beispielen ist das Abschlusszeichen (\ 0). Dies ist für die MySQL-Konsolenausgabe unsichtbar und kann von keiner der oben genannten Abfragen erkannt werden. Die Abfrage, um es zu finden, ist einfach:

select * from TABLE where COLUMN like '%\0%';
Rob Bailey
quelle
4

Basierend auf der richtigen Antwort, aber auch unter Berücksichtigung der ASCII-Steuerzeichen, hat sich für mich folgende Lösung bewährt:

SELECT * FROM `table` WHERE NOT `field` REGEXP  "[\\x00-\\xFF]|^$";

Es funktioniert genauso: Es wird in einer Spalte nach Verstößen gegen den ASCII-Bereich gesucht, aber Sie können auch nach Steuerzeichen suchen, da für Codepunkte die hexadezimale Notation verwendet wird. Da es keinen Vergleich oder keine Konvertierung gibt (im Gegensatz zu @ Ollie's Antwort), sollte dies auch deutlich schneller sein. (Vor allem, wenn MySQL die Regex-Abfrage vorzeitig beendet, was auf jeden Fall der Fall sein sollte.)

Außerdem wird vermieden, dass Felder mit der Länge Null zurückgegeben werden. Wenn Sie eine etwas längere Version wünschen, die möglicherweise eine bessere Leistung erzielt, können Sie stattdessen Folgendes verwenden:

SELECT * FROM `table` WHERE `field` <> "" AND NOT `field` REGEXP  "[\\x00-\\xFF]";

Es wird eine separate Längenprüfung durchgeführt, um Ergebnisse mit einer Länge von Null zu vermeiden, ohne sie für einen Regex-Durchlauf zu berücksichtigen. Abhängig von der Anzahl der Einträge mit der Länge Null kann dies erheblich schneller sein.

Beachten Sie, dass wenn Ihr Standardzeichensatz etwas Seltsames ist, bei dem 0x00-0xFF nicht denselben Werten wie ASCII zugeordnet ist (gibt es irgendwo einen solchen Zeichensatz?), Dies ein falsches Positiv zurückgeben würde. Ansonsten viel Spaß!

Mahmoud Al-Qudsi
quelle
1
00-FF enthält alle möglichen 8-Bit-Werte, was REGEXPüberprüft wird. Daher ist garantiert, dass es immer übereinstimmt. Auch ^$ist wahrscheinlich nicht das, was Sie wollten.
Rick James
Auf jeden Fall die beste REGEXP-Lösung zum Auffinden aller 8-Bit-Zeichen, aber nicht so gut wie die CONVERT-Lösung (col USING charset), die auch Steuerzeichen ermöglicht und Anzeigezeichen auf einen bestimmten Zeichensatz beschränkt.
Ian
1

Versuchen Sie, diese Abfrage zum Durchsuchen von Sonderzeichendatensätzen zu verwenden

SELECT *
FROM tableName
WHERE fieldName REGEXP '[^a-zA-Z0-9@:. \'\-`,\&]'
Sachin
quelle
0

Die Antwort von @ zende war die einzige, die Spalten mit einer Mischung aus ASCII- und Nicht-ASCII-Zeichen abdeckte, aber sie hatte auch diese problematische Hex-Sache. Ich habe das benutzt:

SELECT * FROM `table` WHERE NOT `column` REGEXP '^[ -~]+$' AND `column` !=''
chiliNUT
quelle
0

In Oracle können wir unten verwenden.

SELECT * FROM TABLE_A WHERE ASCIISTR(COLUMN_A) <> COLUMN_A;
Malaka Gunawardhana
quelle
-2

Für diese Frage können wir auch diese Methode verwenden:

Frage vom sql zoo: Hier
finden Sie alle Details zu dem von PETER GRÜNBERG gewonnenen Preis

Nicht-ASCII-Zeichen

ans: wähle * aus nobel wo Gewinner wie 'P% GR% _% berg';

hemu123
quelle
1
Wo ist die Verbindung zur Frage?
Nico Haase