Como faço para grep para todos os caracteres não-ASCII?

Eu tenho vários arquivos XML muito grandes e estou tentando encontrar as linhas que contêm caracteres não-ASCII. Eu tentei o seguinte:

grep -e "[\x{00FF}-\x{FFFF}]" file.xml 

Mas isso retorna todas as linhas do arquivo, independentemente de a linha conter um caractere no intervalo especificado.

Eu tenho a syntax errada ou estou fazendo algo errado? Eu também tentei:

 egrep "[\x{00FF}-\x{FFFF}]" file.xml 

(com aspas simples e duplas em torno do padrão).

Você pode usar o comando:

 grep --color='auto' -P -n "[\x80-\xFF]" file.xml 

Isso fornecerá o número da linha e destacará os caracteres não-ascii em vermelho.

Em alguns sistemas, dependendo de suas configurações, o acima não funcionará, então você pode grep pelo inverso

 grep --color='auto' -P -n "[^\x00-\x7F]" file.xml 

Note também que o bit importante é o flag -P que equivale a --perl-regexp : então ele interpretará seu padrão como uma expressão regular Perl. Também diz que

isso é altamente experimental e grep -P pode avisar sobre resources não implementados.

Em vez de fazer suposições sobre o intervalo de bytes de caracteres não-ASCII, como a maioria das soluções acima, é um IMO um pouco melhor para ser explícito sobre o intervalo de bytes real de caracteres ASCII.

Então a primeira solução, por exemplo, seria:

 grep --color='auto' -P -n '[^\x00-\x7F]' file.xml 

(que basicamente é usado para qualquer caractere fora do intervalo ASCII hexadecimal: de \ x00 a \ x7F)

No Mountain Lion que não funciona (devido à falta de suporte PCRE no BSD grep) , mas com o pcre instalado via Homebrew, o seguinte também funcionará:

 pcregrep --color='auto' -n '[^\x00-\x7F]' file.xml 

Quaisquer prós ou contras que alguém possa pensar?

O seguinte funciona para mim:

 grep -P "[\x80-\xFF]" file.xml 

Caracteres não-ASCII começam em 0x80 e vão para 0xFF ao analisar bytes. O grep (e a família) não fazem o processamento Unicode para mesclar caracteres de múltiplos bytes em uma única entidade para correspondência de regex como você deseja. A opção -P no meu grep permite o uso de \xdd escapa em classs de caracteres para realizar o que você deseja.

Em perl

 perl -ane '{ if(m/[[:^ascii:]]/) { print } }' fileName > newFile 

A maneira mais fácil é definir um caractere não-ASCII … como um caractere que não é um caractere ASCII.

 LC_ALL=C grep '[^ -~]' file.xml 

Adicione um separador após o ^ se necessário.

Definindo LC_COLLATE=C evita surpresas desagradáveis ​​sobre o significado dos intervalos de caracteres em muitos locais. A configuração LC_CTYPE=C é necessária para corresponder aos caracteres de byte único – caso contrário, o comando perderia seqüências de bytes inválidos na codificação atual. Definindo LC_ALL=C evita efeitos dependentes de código de idioma.

Aqui está outra variante que achei que produziu resultados completamente diferentes da pesquisa grep para [\x80-\xFF] na resposta aceita. Talvez seja útil para alguém encontrar outros caracteres não-ascii:

grep --color='auto' -P -n "[^[:ascii:]]" myfile.txt

Nota: o grep do meu computador (um Mac) não tinha a opção -P , por isso ggrep brew install grep e iniciei a chamada acima com ggrep vez de grep .

O código a seguir funciona:

 find /tmp | perl -ne 'print if /[^[:ascii:]]/' 

Substitua /tmp pelo nome do diretório pelo qual você deseja pesquisar.

Estranhamente, eu tive que fazer isso hoje! Eu acabei usando o Perl porque não consegui fazer o grep / egrep funcionar (mesmo no modo -P). Algo como:

 cat blah | perl -en '/\xCA\xFE\xBA\xBE/ && print "found"' 

Para caracteres unicode (como \u2212 no exemplo abaixo) use isto:

 find . ... -exec perl -CA -e '$ARGV = @ARGV[0]; open IN, $ARGV; binmode(IN, ":utf8"); binmode(STDOUT, ":utf8"); while () { next unless /\N{U+2212}/; print "$ARGV: $&: $_"; exit }' '{}' \; 

Procurando por caracteres não imprimíveis.

Eu concordo com Harvey acima enterrado nos comentários, muitas vezes é mais útil procurar por caracteres não imprimíveis OU é fácil pensar não-ASCII quando você realmente deveria estar pensando não imprimível. Harvey sugere “use isto:” [^ \ n – ~] “. Adicione \ r para arquivos de texto DOS. Isso se traduz em” [^ \ x0A \ x020- \ x07E] “e adicione \ x0D para CR”

Além disso, adicionar -c (show count de padrões combinados) ao grep é útil ao procurar caracteres não imprimíveis, já que as strings correspondidas podem atrapalhar o terminal.

Eu encontrei adicionando intervalo 0-8 e 0x0e-0x1f (para o intervalo 0x80-0xff) é um padrão útil. Isso exclui o TAB, CR e LF e um ou dois caracteres imprimíveis incomuns. Então IMHO um padrão grep bastante útil (embora bruto) é este:

 grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" * 

demolir:

 \x00-\x08 - non-printable control chars 0 - 7 decimal \x0E-\x1F - more non-printable control chars 14 - 31 decimal \x80-1xFF - non-printable chars > 128 decimal -c - print count of matching lines instead of lines -P - perl style regexps Instead of -c you may prefer to use -n (and optionally -b) or -l -n, --line-number -b, --byte-offset -l, --files-with-matches 

Por exemplo, um exemplo prático de uso encontra para grep todos os arquivos no diretório atual:

 find . -type f -exec grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" {} + 

Você pode querer ajustar o grep às vezes. Por exemplo, o caractere BS (0x08 – backspace) usado em alguns arquivos imprimíveis ou para excluir o VT (0x0B – tabulação vertical). Os caracteres BEL (0x07) e ESC (0x1B) também podem ser considerados imprimíveis em alguns casos.

 Non-Printable ASCII Chars ** marks PRINTABLE but CONTROL chars that is useful to exclude sometimes Dec Hex Ctrl Char description Dec Hex Ctrl Char description 0 00 ^@ NULL 16 10 ^P DATA LINK ESCAPE (DLE) 1 01 ^A START OF HEADING (SOH) 17 11 ^Q DEVICE CONTROL 1 (DC1) 2 02 ^B START OF TEXT (STX) 18 12 ^R DEVICE CONTROL 2 (DC2) 3 03 ^C END OF TEXT (ETX) 19 13 ^S DEVICE CONTROL 3 (DC3) 4 04 ^D END OF TRANSMISSION (EOT) 20 14 ^T DEVICE CONTROL 4 (DC4) 5 05 ^E END OF QUERY (ENQ) 21 15 ^U NEGATIVE ACKNOWLEDGEMENT (NAK) 6 06 ^F ACKNOWLEDGE (ACK) 22 16 ^V SYNCHRONIZE (SYN) 7 07 ^G BEEP (BEL) 23 17 ^W END OF TRANSMISSION BLOCK (ETB) 8 08 ^H BACKSPACE (BS)** 24 18 ^X CANCEL (CAN) 9 09 ^I HORIZONTAL TAB (HT)** 25 19 ^Y END OF MEDIUM (EM) 10 0A ^J LINE FEED (LF)** 26 1A ^Z SUBSTITUTE (SUB) 11 0B ^K VERTICAL TAB (VT)** 27 1B ^[ ESCAPE (ESC) 12 0C ^L FF (FORM FEED)** 28 1C ^\ FILE SEPARATOR (FS) RIGHT ARROW 13 0D ^M CR (CARRIAGE RETURN)** 29 1D ^] GROUP SEPARATOR (GS) LEFT ARROW 14 0E ^N SO (SHIFT OUT) 30 1E ^^ RECORD SEPARATOR (RS) UP ARROW 15 0F ^O SI (SHIFT IN) 31 1F ^_ UNIT SEPARATOR (US) DOWN ARROW 

Pode ser interessante saber como procurar um caractere unicode. Este comando pode ajudar. Você só precisa saber o código em UTF8

 grep -v $'\u200d'