Bagaimana cara menemukan karakter non-ASCII di MySQL?

124

Saya bekerja dengan database MySQL yang beberapa datanya diimpor dari Excel . Data berisi karakter non- ASCII (tanda pisah em, dll.) Serta carriage return atau baris feed yang tersembunyi. Apakah ada cara untuk menemukan record ini menggunakan MySQL?

Ed Mays
sumber
8
Ollie Jones memiliki jawaban yang jauh lebih baik (periksa bagian bawah).
Jonathan Arkell
1
@JonathanArkell Tidak lagi di bawah :)
Brilliand
Koreksi .. periksa bagian tengah! ;)
Jonathan Arkell
Ini adalah jawaban yang dibicarakan oleh @Jonathan tentang stackoverflow.com/a/11741314/792066
Braiam

Jawaban:

64

Itu tergantung persis apa yang Anda definisikan sebagai "ASCII", tetapi saya menyarankan untuk mencoba varian kueri seperti ini:

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

Kueri tersebut akan mengembalikan semua baris di mana columnToCheck berisi karakter non-alfanumerik. Jika Anda memiliki karakter lain yang dapat diterima, tambahkan ke kelas karakter dalam ekspresi reguler. Misalnya, jika titik, koma, dan tanda hubung OK, ubah kueri menjadi:

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

Halaman paling relevan dari dokumentasi MySQL mungkin adalah 12.5.2 Regular Expressions .

Chad Birch
sumber
3
Tidakkah sebaiknya Anda lepas dari tanda hubung dan titik? (Karena mereka memiliki arti khusus dalam ekspresi reguler.) SELECT * FROM tableName WHERE NOT columnToCheck REGEXP '[A-Za-z0-9 \., \ -]';
Tooony
3
@Tooony Tidak, di dalam himpunan, titik hanya berarti dirinya sendiri dan tanda hubung hanya memiliki arti khusus di antara karakter lain. Di akhir set, itu hanya berarti dirinya sendiri.
Michael Speer
10
Kueri ini hanya menemukan semua baris di tableName yang tidak mengandung karakter alfanumerik. Ini tidak menjawab pertanyaan itu.
Rob Bailey
8
Itu untuk kolom yang tidak memiliki karakter ascii sama sekali, jadi kolom dengan campuran karakter ascii dan non-ascii akan terlewat. Jawaban di bawah ini dari zende memeriksa satu atau lebih karakter non-ascii. Ini sebagian besar membantu sayaSELECT * FROM tbl WHERE colname NOT REGEXP '^[A-Za-z0-9\.,@&\(\) \-]*$';
Frank Forte
1
Ini hanya berfungsi (bagi saya) untuk menemukan string yang tidak berisi karakter tersebut. Itu tidak menemukan string yang berisi campuran karakter ASCII dan non-ASCII.
Ian
236

MySQL menyediakan manajemen rangkaian karakter komprehensif yang dapat membantu mengatasi masalah semacam ini.

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

The CONVERT(col USING charset)Fungsi mengubah karakter unconvertable menjadi karakter pengganti. Kemudian, teks yang dikonversi dan teks yang belum dikonversi akan menjadi tidak sama.

Lihat ini untuk diskusi lebih lanjut. https://dev.mysql.com/doc/refman/8.0/en/charset-repertoire.html

Anda dapat menggunakan nama set karakter apa pun yang Anda inginkan sebagai pengganti ASCII. Misalnya, jika Anda ingin mengetahui karakter mana yang tidak ditampilkan dengan benar di halaman kode 1257 (Lituavi, Latvia, Estonia) gunakanCONVERT(columnToCheck USING cp1257)

O. Jones
sumber
20
Ini adalah solusi terbaik untuk masalah ini dan jauh lebih kuat.
CraigDouglas
5
ini juga berguna untuk menemukan karakter dengan aksen (á ä dll) atau karakter yang tidak termasuk dalam pengkodean
Glasnhost
3
jauh lebih baik daripada menggunakan REGEXP (yang sepertinya tidak berhasil bagi saya untuk menemukan aksen) dan juga menyediakan mekanisme sederhana untuk membuat semuanya menjadi ascii lagi ...
Dirk Conrad Coetsee
1
Jawaban ini bekerja dengan sangat baik dan akan menampilkan string yang berisi karakter non-ASCII, bukan hanya string yang hanya berisi karakter non-ASCII. Terima kasih!
Ian
2
Solusi luar biasa!
Mad Dog Tannen
93

Anda dapat menentukan ASCII sebagai semua karakter yang memiliki nilai desimal 0 - 127 (0x00 - 0x7F) dan menemukan kolom dengan karakter non-ASCII menggunakan kueri berikut

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

Ini adalah pertanyaan paling komprehensif yang dapat saya temukan.

zende
sumber
3
Jawaban terbaik sejauh ini, tetapi lebih mudah seperti ini:SELECT * FROM table WHERE LENGTH( column ) != CHAR_LENGTH( column )
SuN
15
-1 Ini dapat menghasilkan hasil yang salah. Misalkan, misalnya, seseorang memiliki kolom UTF-16 yang berisi 'ā'(dikodekan oleh urutan byte 0x0101) - itu akan dianggap "ASCII" menggunakan tes ini: negatif palsu ; memang, beberapa rangkaian karakter tidak karakter ASCII encode dalam 0x00ke 0x7fdimana solusi ini akan menghasilkan positif palsu. JANGAN MENGANDALKAN JAWABAN INI!
eggyal
2
@sun: Itu tidak membantu sama sekali - banyak himpunan karakter memiliki panjang tetap sehingga LENGTH(column)akan menjadi kelipatan konstan CHAR_LENGTH(column)terlepas dari nilainya.
eggyal
49

Ini mungkin yang Anda cari:

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

Ini harus mengembalikan semua baris di mana COLUMN berisi karakter non-ASCII (atau karakter ASCII yang tidak dapat dicetak seperti baris baru).

Peter Mortensen
sumber
7
Sangat cocok untuk saya. "regexp '[^ - ~]'" berarti memiliki karakter sebelum spasi "" atau setelah "~" atau ASCII 32 - 126. Semua huruf, angka, dan simbol, tetapi tidak ada yang tidak dapat dicetak.
Josh
Anda bahkan bisa mendapatkannya sebagai kaos;) catonmat.net/blog/my-favorite-regex
SamGoody
1
Perhatikan peringatan di dokumentasi : " The REGEXPdan RLIKE. Operator bekerja dalam mode byte-bijaksana, sehingga mereka tidak multi-byte aman dan dapat menghasilkan hasil yang tidak diharapkan dengan karakter set multi-byte Selain itu, operator ini membandingkan karakter dengan nilai-nilai byte dan karakter beraksen mungkin tidak dapat dibandingkan sebagai sama meskipun
susunan yang
1
Terima kasih untuk ini. yang saya ingin tahu adalah bagaimana cara mengganti karakter pengganti - misalnya â
mars-o
1
@ mars-o - berlian hitam menunjukkan karakter utf8 yang tidak valid. Diskusi lebih lanjut di sini
Rick James
14

Satu karakter yang hilang dari contoh semua orang di atas adalah karakter terminasi (\ 0). Ini tidak terlihat oleh keluaran konsol MySQL dan tidak dapat ditemukan oleh salah satu kueri yang disebutkan sebelumnya. Kueri untuk menemukannya adalah:

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

Berdasarkan jawaban yang benar, tetapi dengan mempertimbangkan karakter kontrol ASCII juga, solusi yang berhasil untuk saya adalah ini:

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

Itu melakukan hal yang sama: mencari pelanggaran rentang ASCII di kolom, tetapi memungkinkan Anda mencari karakter kontrol juga, karena menggunakan notasi heksadesimal untuk poin kode. Karena tidak ada perbandingan atau konversi (tidak seperti jawaban @ Ollie), ini seharusnya jauh lebih cepat juga. (Terutama jika MySQL melakukan penghentian awal pada kueri regex, yang memang seharusnya dilakukan.)

Ini juga menghindari kembali bidang yang panjangnya nol. Jika Anda menginginkan versi yang sedikit lebih panjang yang mungkin berkinerja lebih baik, Anda dapat menggunakan ini sebagai gantinya:

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

Itu melakukan pemeriksaan terpisah untuk panjang untuk menghindari hasil panjang-nol, tanpa mempertimbangkannya untuk regex pass. Bergantung pada jumlah entri panjang-nol yang Anda miliki, ini bisa jauh lebih cepat.

Perhatikan bahwa jika kumpulan karakter default Anda adalah sesuatu yang aneh di mana 0x00-0xFF tidak dipetakan ke nilai yang sama seperti ASCII (apakah ada kumpulan karakter seperti itu di mana saja?), Ini akan mengembalikan positif palsu. Jika tidak, selamat menikmati!

Mahmoud Al-Qudsi
sumber
1
00-FF menyertakan semua kemungkinan nilai 8-bit, yang REGEXPdiperiksa. Makanya di jamin selalu cocok. Juga ^$mungkin bukan apa yang Anda inginkan.
Rick James
Jelas merupakan solusi REGEXP terbaik untuk menemukan semua karakter 8 bit tetapi tidak sebaik solusi CONVERT (col USING charset) yang juga akan memungkinkan karakter kontrol sementara membatasi karakter tampilan ke charset tertentu.
Ian
1

Coba gunakan kueri ini untuk mencari rekaman karakter khusus

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

Jawaban @zende adalah satu-satunya jawaban yang menutupi kolom dengan campuran karakter ascii dan non ascii, tetapi juga memiliki hex yang bermasalah. Saya menggunakan ini:

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

Di Oracle kita bisa gunakan di bawah ini.

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

untuk pertanyaan ini kita juga bisa menggunakan metode ini:

Pertanyaan dari sql zoo:
Temukan semua detail hadiah yang dimenangkan oleh PETER GRÜNBERG

Karakter non-ASCII

ans: pilih * dari nobel dimana pemenangnya menyukai'P% GR% _% berg ';

hemu123
sumber
1
Dimana hubungannya dengan pertanyaan itu?
Nico Haase