Como posso encontrar caracteres não ASCII no MySQL?


124

Estou trabalhando com um banco de dados MySQL que possui alguns dados importados do Excel . Os dados contêm caracteres não ASCII (traços, etc.), bem como retornos de carro ocultos ou avanços de linha. Existe uma maneira de encontrar esses registros usando o MySQL?


8
Ollie Jones tem uma resposta muito melhor (veja a parte inferior).
11134 Jonathan Arcell

1
@JonathanArkell Não na parte inferior mais :)
Brilliand

Correção .. verifique o meio! ;)
Jonathan Arkell

Esta é a resposta @ Jonathan está falando sobre stackoverflow.com/a/11741314/792066
Braiam

Respostas:


64

Depende exatamente do que você está definindo como "ASCII", mas eu sugiro tentar uma variante de uma consulta como esta:

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

Essa consulta retornará todas as linhas em que columnToCheck contém caracteres não alfanuméricos. Se você tiver outros caracteres aceitáveis, adicione-os à classe de caracteres na expressão regular. Por exemplo, se pontos, vírgulas e hífens estiverem OK, altere a consulta para:

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

A página mais relevante da documentação do MySQL é provavelmente 12.5.2 Expressões regulares .


3
Você não deveria escapar do hífen e do período? (Como eles têm significados especiais em uma expressão regular.) SELECT * FROM tableName WHERE NOT columnToCheck REGEXP '[A-Za-z0-9 \., \ -]';
Tooony 12/03/09

3
@Tooony Não, dentro de um conjunto, um ponto significa apenas a si mesmo e o traço só tem um significado especial entre outros caracteres. No final do set, significa apenas ele mesmo.
Michael Speer

10
Esta consulta localiza apenas todas as linhas em tableName que não contêm um caractere alfanumérico. Isso não responde à pergunta.
Rob Bailey

8
Isso é para colunas que não possuem nenhum caractere ASCII; portanto, ele perderá aqueles com uma mistura de caracteres ASCII e não ASCII. A resposta abaixo do zende verifica se há um ou mais caracteres não-ascii. Isso me ajudou em sua maior parte #SELECT * FROM tbl WHERE colname NOT REGEXP '^[A-Za-z0-9\.,@&\(\) \-]*$';
Frank Forte

1
Isso só funciona (para mim de qualquer maneira) para encontrar cadeias que contenham NENHUM desses caracteres. Ele não encontra seqüências que contêm uma mistura de caracteres ASCII e não ASCII.
Ian

236

O MySQL fornece gerenciamento abrangente de conjunto de caracteres que pode ajudar com esse tipo de problema.

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

A CONVERT(col USING charset)função transforma os caracteres não conversíveis em caracteres de substituição. Em seguida, o texto convertido e não convertido será desigual.

Veja isso para mais discussão. https://dev.mysql.com/doc/refman/8.0/en/charset-repertoire.html

Você pode usar qualquer nome de conjunto de caracteres que desejar no lugar de ASCII. Por exemplo, se você deseja descobrir quais caracteres não serão renderizados corretamente na página de código 1257 (lituano, letão, estoniano), useCONVERT(columnToCheck USING cp1257)


20
Esta é uma excelente solução para esse problema e muito mais robusta.
CraigDouglas

5
isso também é útil para encontrar caracteres com acentos (á etc) ou caracteres que não pertencem à codificação.
Glasnhost

3
muito melhor do que usando REGEXP (que parece não trabalho para mim para encontrar acentos) e também fornece um mecanismo simples para fazer tudo ascii de novo ...
Dirk Conrad Coetsee

1
Essa resposta funciona maravilhosamente e exibirá cadeias que contêm caracteres não ASCII em vez de apenas cadeias que contêm apenas caracteres não ASCII. Obrigado!
Ian

2
Excelente solução!
Mad Dog Tannen

93

Você pode definir ASCII como todos os caracteres que tenham um valor decimal de 0 a 127 (0x00 - 0x7F) e localizar colunas com caracteres não ASCII usando a consulta a seguir

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

Essa foi a consulta mais abrangente que eu pude fazer.


3
A melhor resposta até agora, mas é ainda mais fácil assim::SELECT * FROM table WHERE LENGTH( column ) != CHAR_LENGTH( column )
28/11

15
-1 Isso pode produzir resultados incorretos. Suponha, por exemplo, que se tenha uma coluna UTF-16 contendo 'ā'(codificada pela sequência de bytes 0x0101) - seria considerada "ASCII" usando este teste: um falso negativo ; de fato, alguns conjuntos de caracteres não codificam caracteres ASCII dentro 0x00dos quais 0x7fessa solução produziria um falso positivo. NÃO CONFIE NESTA RESPOSTA!
eggyal

2
@sun: Isso não ajuda em nada - muitos conjuntos de caracteres são de comprimento fixo e, portanto LENGTH(column), será um múltiplo constante, CHAR_LENGTH(column)independentemente do valor.
eggyal

49

Provavelmente é isso que você está procurando:

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

Ele deve retornar todas as linhas em que COLUMN contém caracteres não ASCII (ou caracteres ASCII não imprimíveis, como nova linha).


7
Funciona muito bem para mim. "regexp '[^ - ~]'" significa que possui um caractere que está antes do espaço "" ou depois de "~" ou ASCII 32 - 126. Todas as letras, números e símbolos, mas nada imprimível.
Josh

Você ainda pode obtê-lo como um T-shirt;) catonmat.net/blog/my-favorite-regex
SamGoody

1
Observe o aviso na documentação : " Os operadores REGEXPe RLIKEfuncionam de maneira byte, portanto, não são seguros para vários bytes e podem produzir resultados inesperados com conjuntos de caracteres de vários bytes. Além disso, esses operadores comparam caracteres por seus valores de bytes e caracteres acentuados podem não são considerados iguais mesmo se um determinado trata de agrupamento-los como iguais. "
eggyal

1
obrigado por isso. o que eu estou querendo saber é como substituir um caractere de substituição - por exemplo, um
mars-o

1
@ mars-o - o diamante preto indica um caractere utf8 inválido. Mais discussão aqui
Rick James

14

Um caractere ausente dos exemplos de todos acima é o caractere de terminação (\ 0). Isso é invisível para a saída do console do MySQL e não pode ser descoberto por nenhuma das consultas mencionadas anteriormente. A consulta para encontrá-lo é simplesmente:

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

4

Com base na resposta correta, mas levando em consideração os caracteres de controle ASCII, a solução que funcionou para mim é a seguinte:

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

Ele faz o mesmo: pesquisa violações do intervalo ASCII em uma coluna, mas permite pesquisar caracteres de controle também, pois ele usa notação hexadecimal para pontos de código. Como não há comparação ou conversão (diferente da resposta de @ Ollie), isso também deve ser significativamente mais rápido. (Especialmente se o MySQL fizer o encerramento antecipado na consulta regex, o que definitivamente deveria.)

Também evita retornar campos com comprimento zero. Se você deseja uma versão um pouco mais longa que possa ter um desempenho melhor, use-a:

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

Ele faz uma verificação separada do comprimento para evitar resultados de comprimento zero, sem considerá-los para um passe de regex. Dependendo do número de entradas de tamanho zero que você possui, isso pode ser significativamente mais rápido.

Observe que, se o conjunto de caracteres padrão for algo bizarro, em que 0x00-0xFF não mapeie para os mesmos valores que ASCII (existe um conjunto de caracteres em algum lugar?), Isso retornaria um falso positivo. Caso contrário, aproveite!


1
00-FF inclui todos os valores possíveis de 8 bits, que é o que REGEXPestá verificando. Por isso, é garantido que sempre corresponda. Também ^$provavelmente não é o que você queria.
Rick James

Definitivamente, a melhor solução REGEXP para encontrar todos os caracteres de 8 bits, mas não tão boa quanto a solução CONVERT (col USING charset), que também permite controlar caracteres, limitando os caracteres de exibição a um conjunto de caracteres específico.
25418 Ian

1

Tente usar esta consulta para pesquisar registros de caracteres especiais

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

0

A resposta de @ zende foi a única que cobriu as colunas com uma mistura de caracteres ascii e não ascii, mas também tinha essa coisa hexadecimal problemática. Eu usei isso:

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


-2

para esta pergunta, também podemos usar este método:

Pergunta do sql zoo:
encontre todos os detalhes do prêmio ganho por PETER GRÜNBERG

Caracteres não ASCII

ans: selecione * do nobel onde o vencedor gosta de 'P% GR% _% berg';


1
Onde está a conexão com a pergunta?
Nico Haase
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.