¿Cómo puedo encontrar caracteres no ASCII en MySQL?

124

Estoy trabajando con una base de datos MySQL que tiene algunos datos importados de Excel . Los datos contienen caracteres no ASCII (guiones largos, etc.), así como retornos de carro ocultos o avances de línea. ¿Hay alguna manera de encontrar estos registros usando MySQL?

Ed Mays
fuente
8
Ollie Jones tiene una respuesta mucho mejor (verifique la parte inferior).
Jonathan Arkell el
1
@JonathanArkell Ya no está en la parte inferior :)
Brilliand
Corrección .. verifique el medio! ;)
Jonathan Arkell
Esta es la respuesta @Jonathan está hablando de stackoverflow.com/a/11741314/792066
Braiam

Respuestas:

64

Depende exactamente de lo que esté definiendo como "ASCII", pero sugeriría probar una variante de una consulta como esta:

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

Esa consulta devolverá todas las filas donde columnToCheck contiene caracteres no alfanuméricos. Si tiene otros caracteres que son aceptables, agréguelos a la clase de caracteres en la expresión regular. Por ejemplo, si los puntos, las comas y los guiones están bien, cambie la consulta a:

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

La página más relevante de la documentación de MySQL es probablemente 12.5.2 Expresiones regulares .

Abedul Chad
fuente
3
¿No deberías escapar del guión y punto? (Ya que tienen significados especiales en una expresión regular.) SELECT * FROM tableName WHERE NOT columnToCheck REGEXP '[A-Za-z0-9 \., \ -]';
Tooony
3
@Tooony No, dentro de un conjunto, un punto solo significa sí mismo y el guión solo tiene un significado especial entre otros caracteres. Al final del set, solo significa a sí mismo.
Michael Speer el
10
Esta consulta solo encuentra todas las líneas en tableName que no contienen un carácter alfanumérico. Esto no responde la pregunta.
Rob Bailey
8
Eso es para columnas que no tienen ningún carácter ASCII en absoluto, por lo que los extrañará con una mezcla de caracteres ASCII y no ASCII. La respuesta a continuación de zende busca uno o más caracteres no ascii. Esto me ayudó en su mayor parteSELECT * FROM tbl WHERE colname NOT REGEXP '^[A-Za-z0-9\.,@&\(\) \-]*$';
Frank Forte el
1
Esto solo funciona (para mí de todos modos) para encontrar cadenas que contengan NINGUNO de esos caracteres. No encuentra cadenas que contengan una combinación de caracteres ASCII y no ASCII.
Ian
236

MySQL proporciona una gestión integral del juego de caracteres que puede ayudar con este tipo de problema.

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

La CONVERT(col USING charset)función convierte los caracteres no convertibles en caracteres de reemplazo. Entonces, el texto convertido y no convertido será desigual.

Vea esto para más discusión. https://dev.mysql.com/doc/refman/8.0/en/charset-repertoire.html

Puede usar cualquier nombre de juego de caracteres que desee en lugar de ASCII. Por ejemplo, si desea averiguar qué caracteres no se mostrarán correctamente en la página de códigos 1257 (lituano, letón, estonio) useCONVERT(columnToCheck USING cp1257)

O. Jones
fuente
20
Esta es una excelente solución a este problema y mucho más robusta.
CraigDouglas
55
esto también es útil para encontrar caracteres con acentos (á ä etc.) o caracteres que no pertenecen a la codificación
Glasnhost
3
mucho mejor que usar REGEXP (que no parece funcionar para mí para encontrar acentos) y también proporciona un mecanismo simple para hacer que todo vuelva a ser tan ascii ...
Dirk Conrad Coetsee
1
Esta respuesta funciona maravillosamente y mostrará cadenas que contienen caracteres que no son ASCII en lugar de solo cadenas que contienen solo caracteres que no son ASCII. ¡Gracias!
Ian
2
¡Solución excepcional!
Mad Dog Tannen
93

Puede definir ASCII como todos los caracteres que tienen un valor decimal de 0 a 127 (0x00 - 0x7F) y buscar columnas con caracteres no ASCII utilizando la siguiente consulta

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

Esta fue la consulta más completa que se me ocurrió.

Zende
fuente
3
La mejor respuesta hasta ahora, pero es aún más fácil de esta manera:SELECT * FROM table WHERE LENGTH( column ) != CHAR_LENGTH( column )
SuN
15
-1 Esto puede arrojar resultados erróneos. Supongamos, por ejemplo, que uno tiene una columna UTF-16 que contiene 'ā'(codificada por la secuencia de bytes 0x0101): se consideraría "ASCII" con esta prueba: un falso negativo ; de hecho, algunos conjuntos de caracteres no codifican caracteres ASCII dentro 0x00de los 0x7fcuales esta solución produciría un falso positivo. ¡NO CONFÍE EN ESTA RESPUESTA!
eggyal
2
@sun: Eso no ayuda en absoluto: muchos conjuntos de caracteres son de longitud fija y, por LENGTH(column)lo tanto , serán un múltiplo constante CHAR_LENGTH(column)independientemente del valor.
eggyal
49

Esto es probablemente lo que estás buscando:

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

Debería devolver todas las filas donde COLUMN contiene caracteres no ASCII (o caracteres ASCII no imprimibles como la nueva línea).

Peter Mortensen
fuente
77
Funciona muy bien para mi. "regexp '[^ - ~]'" significa que tiene un carácter antes del espacio "" o después de "~" o ASCII 32 - 126. Todas las letras, números y símbolos, pero no elementos no imprimibles.
Josh
Incluso puede obtenerlo como una camiseta;) catonmat.net/blog/my-favorite-regex
SamGoody
1
Tenga en cuenta la advertencia en la documentación : " Los operadores REGEXPy RLIKEfuncionan de manera byte-byte, por lo que no son seguros para varios bytes y pueden producir resultados inesperados con conjuntos de caracteres de varios bytes. Además, estos operadores comparan los caracteres por sus valores de byte y los caracteres acentuados pueden no compararse como iguales, incluso si una colación dada los trata como iguales. "
eggyal
1
gracias por esto. Lo que me pregunto es cómo reemplazar un personaje de reemplazo, por ejemplo
mars-o
1
@ mars-o: el diamante negro indica un carácter utf8 no válido. Más discusión aquí
Rick James
14

Un carácter que falta en los ejemplos de todos los anteriores es el carácter de terminación (\ 0). Esto es invisible para la salida de la consola MySQL y no puede ser detectado por ninguna de las consultas mencionadas anteriormente. La consulta para encontrarlo es simplemente:

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

Según la respuesta correcta, pero teniendo en cuenta también los caracteres de control ASCII, la solución que funcionó para mí es esta:

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

Hace lo mismo: busca violaciones del rango ASCII en una columna, pero también le permite buscar caracteres de control, ya que utiliza la notación hexadecimal para los puntos de código. Como no hay comparación o conversión (a diferencia de la respuesta de @ Ollie), esto también debería ser significativamente más rápido. (Especialmente si MySQL hace una terminación anticipada en la consulta de expresiones regulares, que definitivamente debería).

También evita la devolución de campos de longitud cero. Si desea una versión un poco más larga que funcione mejor, puede usar esto en su lugar:

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

Hace una verificación de longitud por separado para evitar resultados de longitud cero, sin considerarlos para un pase de expresiones regulares. Dependiendo del número de entradas de longitud cero que tenga, esto podría ser significativamente más rápido.

Tenga en cuenta que si su conjunto de caracteres predeterminado es algo extraño donde 0x00-0xFF no se asigna a los mismos valores que ASCII (¿existe tal conjunto de caracteres en algún lugar?), Esto devolvería un falso positivo. De lo contrario, disfruta!

Mahmoud Al-Qudsi
fuente
1
00-FF incluye todos los valores posibles de 8 bits, que es lo que se REGEXPestá comprobando. Por lo tanto, se garantiza que siempre coincida. También ^$probablemente no es lo que quería.
Rick James
Definitivamente, la mejor solución REGEXP para encontrar todos los caracteres de 8 bits, pero no tan buena como la solución CONVERTIR (col USING charset) que también permite caracteres de control al tiempo que limita los caracteres de visualización a un conjunto de caracteres específico.
Ian
1

Intente usar esta consulta para buscar registros de caracteres especiales

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

La respuesta de @ zende fue la única que cubrió columnas con una mezcla de caracteres ascii y no ascii, pero también tenía esa problemática cuestión hexadecimal. Usé esto:

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

En Oracle podemos usar a continuación.

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

para esta pregunta también podemos usar este método:

Pregunta del zoológico sql:
encuentre todos los detalles del premio ganado por PETER GRÜNBERG

Caracteres no ASCII

ans: seleccione * de nobel donde el ganador como 'P% GR% _% berg';

hemu123
fuente
1
¿Dónde está la conexión con la pregunta?
Nico Haase