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'