ฉันจะค้นหาอักขระที่ไม่ใช่ ASCII ใน MySQL ได้อย่างไร


124

ฉันกำลังทำงานกับฐานข้อมูล MySQL ที่มีข้อมูลบางส่วนที่นำเข้าจากExcel ข้อมูลประกอบด้วยอักขระที่ไม่ใช่ASCII (เช่นเครื่องหมายขีดกลาง ฯลฯ ) รวมทั้งการส่งคืนค่าขนส่งที่ซ่อนอยู่หรือฟีดบรรทัด มีวิธีค้นหาบันทึกเหล่านี้โดยใช้ MySQL หรือไม่?


8
Ollie Jones มีคำตอบที่ดีกว่ามาก (ตรวจสอบด้านล่าง)
Jonathan Arkell

1
@JonathanArkell ไม่ได้อยู่ด้านล่างอีกต่อไป :)
Brilliand

แก้ไข.. ตรวจของกลาง! ;)
Jonathan Arkell

นี่คือคำตอบ
@Jonathan

คำตอบ:


64

ขึ้นอยู่กับสิ่งที่คุณกำหนดให้เป็น "ASCII" แต่ฉันขอแนะนำให้ลองใช้แบบสอบถามในรูปแบบนี้:

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

แบบสอบถามนั้นจะส่งคืนแถวทั้งหมดโดยที่ columnToCheck มีอักขระที่ไม่ใช่ตัวเลขและตัวอักษร หากคุณมีอักขระอื่นที่ยอมรับได้ให้เพิ่มลงในคลาสอักขระในนิพจน์ทั่วไป ตัวอย่างเช่นหากช่วงเวลาเครื่องหมายจุลภาคและขีดกลางตกลงให้เปลี่ยนแบบสอบถามเป็น:

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

หน้าที่เกี่ยวข้องมากที่สุดของเอกสาร MySQL อาจเป็น12.5.2 นิพจน์ปกติ


3
คุณไม่ควรหนียัติภังค์และจุด? (เนื่องจากมีความหมายพิเศษในนิพจน์ทั่วไป) SELECT * FROM tableName WHERE NOT columnToCheck REGEXP '[A-Za-z0-9 \., \ -]';
Tooony

3
@ Tooony ไม่ใช่ภายในเซตจุดนั้นหมายถึงตัวมันเองและขีดมีความหมายพิเศษระหว่างอักขระอื่นเท่านั้น ท้ายเซตมีความหมายแค่ตัวเอง
Michael Speer

10
แบบสอบถามนี้ค้นหาเฉพาะบรรทัดทั้งหมดใน tableName ที่ไม่มีอักขระที่เป็นตัวอักษรและตัวเลขคละกัน สิ่งนี้ไม่ตอบคำถาม
Rob Bailey

8
นั่นคือสำหรับคอลัมน์ที่ไม่มีอักขระ ascii เลยดังนั้นจึงจะพลาดคอลัมน์ที่มีอักขระ ascii และไม่ใช่ ascii ผสมกัน คำตอบด้านล่างจาก zende ตรวจสอบอักขระที่ไม่ใช่ ascii ตั้งแต่หนึ่งตัวขึ้นไป สิ่งนี้ช่วยฉันได้มากที่สุดSELECT * FROM tbl WHERE colname NOT REGEXP '^[A-Za-z0-9\.,@&\(\) \-]*$';
Frank Forte

1
ใช้งานได้ (สำหรับฉันแล้ว) เพื่อค้นหาสตริงที่ไม่มีอักขระเหล่านั้น ไม่พบสตริงที่มีอักขระ ASCII และอักขระที่ไม่ใช่ ASCII ผสมกัน
เอียน

236

MySQL มีการจัดการชุดอักขระที่ครอบคลุมซึ่งสามารถช่วยแก้ปัญหาประเภทนี้ได้

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

CONVERT(col USING charset)ฟังก์ชั่นจะเปิดตัวละคร unconvertable เป็นตัวอักษรทดแทน จากนั้นข้อความที่แปลงและไม่แปลงกลับจะไม่เท่ากัน

ดูสิ่งนี้สำหรับการสนทนาเพิ่มเติม https://dev.mysql.com/doc/refman/8.0/en/charset-repertoire.html

คุณสามารถใช้ชื่อชุดอักขระที่คุณต้องการแทน ASCII ได้ ตัวอย่างเช่นหากคุณต้องการทราบว่าอักขระใดที่แสดงผลไม่ถูกต้องในโค้ดหน้า 1257 (ลิทัวเนียลัตเวียเอสโตเนีย) ให้ใช้CONVERT(columnToCheck USING cp1257)


20
นี่เป็นวิธีแก้ปัญหาที่ยอดเยี่ยมและมีประสิทธิภาพมากขึ้น
CraigDouglas

5
นอกจากนี้ยังมีประโยชน์ในการค้นหาอักขระที่มีสำเนียง (áä ฯลฯ ) หรืออักขระที่ไม่ได้อยู่ในการเข้ารหัส
Glasnhost

3
ดีกว่าการใช้ REGEXP มาก (ซึ่งดูเหมือนจะไม่ได้ผลสำหรับฉันในการค้นหาสำเนียง) และยังมีกลไกง่ายๆในการสร้างทุกอย่างอีกครั้ง ...
Dirk Conrad Coetsee

1
คำตอบนี้ใช้งานได้อย่างยอดเยี่ยมและจะแสดงสตริงที่มีอักขระที่ไม่ใช่ ASCII แทนที่จะเป็นเพียงสตริงที่มีเฉพาะอักขระที่ไม่ใช่ ASCII ขอบคุณ!
เอียน

2
น้ำยาเด็ด!
Mad Dog Tannen

93

คุณสามารถกำหนด ASCII เป็นอักขระทั้งหมดที่มีค่าทศนิยม 0 - 127 (0x00 - 0x7F) และค้นหาคอลัมน์ที่มีอักขระที่ไม่ใช่ ASCII โดยใช้แบบสอบถามต่อไปนี้

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

นี่เป็นคำค้นหาที่ครอบคลุมที่สุดที่ฉันคิดได้


3
คำตอบที่ดีที่สุด แต่มันง่ายกว่านี้อีก:SELECT * FROM table WHERE LENGTH( column ) != CHAR_LENGTH( column )
สุน

15
-1 สิ่งนี้สามารถให้ผลลัพธ์ที่ผิดพลาดได้ ตัวอย่างเช่นสมมติว่าคนหนึ่งมี UTF-16 คอลัมน์ที่มี'ā'(เข้ารหัสโดยลำดับไบต์0x0101) - มันจะถือว่า "ASCII" โดยใช้การทดสอบนี้: ลบเท็จ ; แน่นอนบางชุดตัวอักษรที่ไม่ได้เข้ารหัสอักขระ ASCII ภายใน0x00เพื่อ0x7fครั้นแล้วการแก้ปัญหานี้จะให้ผลผลิตในเชิงบวกเท็จ อย่าวางใจตามคำตอบนี้!
eggyal

2
@sun: นั่นไม่ได้ช่วยเลย - ชุดอักขระจำนวนมากมีความยาวคงที่และLENGTH(column)จะเป็นค่าคงที่CHAR_LENGTH(column)โดยไม่คำนึงถึงค่า
eggyal

49

นี่อาจเป็นสิ่งที่คุณกำลังมองหา:

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

ควรส่งคืนแถวทั้งหมดที่ COLUMN มีอักขระที่ไม่ใช่ ASCII (หรืออักขระ ASCII ที่ไม่สามารถพิมพ์ได้เช่น newline)


7
ใช้งานได้ดีสำหรับฉัน "regexp '[^ - ~]'" หมายถึงมีอักขระที่อยู่ก่อนเว้นวรรค "" หรือหลัง "~" หรือ ASCII 32 - 126 ตัวอักษรตัวเลขและสัญลักษณ์ทั้งหมด แต่ไม่มีสิ่งที่พิมพ์ไม่ได้
Josh

คุณสามารถซื้อเป็นเสื้อทีเชิ้ตก็ได้) catonmat.net/blog/my-favorite-regex
SamGoody

1
หมายเหตุคำเตือนในเอกสารประกอบ : " ตัวดำเนินการREGEXPและRLIKEตัวดำเนินการทำงานแบบไบต์ที่ชาญฉลาดดังนั้นจึงไม่ปลอดภัยแบบหลายไบต์และอาจให้ผลลัพธ์ที่ไม่คาดคิดกับชุดอักขระแบบหลายไบต์นอกจากนี้ตัวดำเนินการเหล่านี้จะเปรียบเทียบอักขระตามค่าไบต์และ อักขระที่เน้นเสียงไม่สามารถเปรียบเทียบได้ว่าเท่ากันแม้ว่าการจัดเรียงจะถือว่าเท่ากันก็ตาม "
eggyal

1
ขอบคุณสำหรับสิ่งนี้. สิ่งที่ฉันสงสัยคือจะเปลี่ยนอักขระทดแทนอย่างไร - เช่น
mars-o

1
@ mars-o - เพชรสีดำระบุอักขระ utf8 ที่ไม่ถูกต้อง อภิปรายเพิ่มเติมที่นี่
Rick James

14

อักขระหนึ่งตัวที่ขาดหายไปจากตัวอย่างของทุกคนด้านบนคืออักขระการยุติ (\ 0) สิ่งนี้มองไม่เห็นกับเอาต์พุตคอนโซล MySQL และไม่สามารถค้นพบได้จากการสืบค้นใด ๆ ที่กล่าวถึงในที่นี้ แบบสอบถามที่จะค้นหามีเพียง:

select * from TABLE where COLUMN like '%\0%';

4

จากคำตอบที่ถูกต้อง แต่คำนึงถึงอักขระควบคุม ASCII ด้วยเช่นกันวิธีแก้ปัญหาที่เหมาะกับฉันคือ:

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

มันทำสิ่งเดียวกัน: ค้นหาการละเมิดช่วง ASCII ในคอลัมน์ แต่ช่วยให้คุณค้นหาอักขระควบคุมได้เช่นกันเนื่องจากใช้สัญกรณ์ฐานสิบหกสำหรับจุดรหัส เนื่องจากไม่มีการเปรียบเทียบหรือการแปลง (ไม่เหมือนคำตอบของ @ Ollie) สิ่งนี้จึงควรเร็วกว่ามากเช่นกัน (โดยเฉพาะอย่างยิ่งถ้า MySQL ทำการยกเลิกก่อนกำหนดในแบบสอบถาม regex ซึ่งควรจะเป็นอย่างแน่นอน)

นอกจากนี้ยังหลีกเลี่ยงการส่งคืนฟิลด์ที่มีความยาวเป็นศูนย์ หากคุณต้องการเวอร์ชันที่ยาวขึ้นเล็กน้อยซึ่งอาจทำงานได้ดีขึ้นคุณสามารถใช้สิ่งนี้แทน:

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

จะทำการตรวจสอบความยาวแยกต่างหากเพื่อหลีกเลี่ยงผลลัพธ์ที่มีความยาวเป็นศูนย์โดยไม่ต้องพิจารณาว่าเป็น regex pass ขึ้นอยู่กับจำนวนรายการที่มีความยาวเป็นศูนย์ซึ่งอาจเร็วกว่ามาก

โปรดทราบว่าหากชุดอักขระเริ่มต้นของคุณเป็นสิ่งที่แปลกประหลาดโดยที่ 0x00-0xFF ไม่ได้จับคู่กับค่าเดียวกันกับ ASCII (มีชุดอักขระเช่นนี้อยู่ที่ใดหรือไม่) สิ่งนี้จะส่งคืนค่าบวกเท็จ มิฉะนั้นสนุก!


1
00-FF รวมค่า 8 บิตที่เป็นไปได้ทั้งหมดซึ่งเป็นสิ่งที่REGEXPตรวจสอบ ดังนั้นจึงรับประกันได้ว่าจะตรงกันเสมอ นอกจากนี้^$อาจไม่ใช่สิ่งที่คุณต้องการ
Rick James

โซลูชัน REGEXP ที่ดีที่สุดสำหรับการค้นหาอักขระ 8 บิตทั้งหมด แต่ไม่ดีเท่าโซลูชัน CONVERT (col USING charset) ซึ่งจะช่วยให้สามารถควบคุมอักขระในขณะที่ จำกัด อักขระที่แสดงไว้เฉพาะชุดอักขระ
Ian

1

ลองใช้แบบสอบถามนี้เพื่อค้นหาระเบียนอักขระพิเศษ

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

0

คำตอบของ @ zende เป็นคำตอบเดียวที่ครอบคลุมคอลัมน์ที่มีอักขระ ascii และไม่ใช่ ascii ผสมกัน แต่ก็มีสิ่งที่เป็นฐานสิบหกที่มีปัญหาเช่นกัน ฉันใช้สิ่งนี้:

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


-2

สำหรับคำถามนี้เราสามารถใช้วิธีนี้:

คำถามจากสวนสัตว์ sql:
ค้นหารายละเอียดทั้งหมดของรางวัลที่ PETER GRÜNBERGได้รับ

อักขระที่ไม่ใช่ ASCII

ans: เลือก * จากโนเบลที่ผู้ชนะเช่น 'P% GR% _% berg';


1
ความเชื่อมโยงกับคำถามอยู่ที่ไหน
Nico Haase
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.