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.
Tenho a sintaxe errada ou estou fazendo outra coisa errada? Eu também tentei:
egrep "[\x{00FF}-\x{FFFF}]" file.xml
(com aspas simples e duplas ao redor do padrão).
Respostas:
Você pode usar o comando:
Isso fornecerá o número da linha e destacará caracteres não-ascii em vermelho.
Em alguns sistemas, dependendo das suas configurações, as opções acima não funcionarão, portanto, você pode esperar pelo inverso
Observe também que o bit importante é a
-P
flag que equivale a--perl-regexp
: portanto, ele interpretará seu padrão como uma expressão regular do Perl. Também diz quefonte
grep
(no OS X 10.8 Mountain Lion), pois não suporta aP
opção.grep
está disponível nadupes
biblioteca do Homebrew (habilite o usobrew tap homebrew/dupes
):brew install grep
dupes
biblioteca é instalarpcre
:brew install pcre
... como parte disso, você obterá opcregrep
utilitário, que pode ser usado da seguinte forma:pcregrep --color='auto' -n "[\x80-\xFF]" file.xml
brew
usuários de Mac , os coreutils do GNU podem ser instalados combrew install coreutils
. Isso lhe dará muitas ferramentas GNU prefixadas com um 'g' - neste caso, useggrep
. Isso deve evitar problemas decorrentes da substituição de um utilitário do sistema, pois os scripts Mac específicos do sistema agora dependem do BSD grep.ag "[\x80-\xFF]" file
você só precisa instalarthe_silver_searcher
Em vez de fazer suposições sobre o intervalo de bytes de caracteres não ASCII, como a maioria das soluções acima, é um pouco melhor que o IMO seja explícito sobre o intervalo real de bytes de caracteres ASCII.
Portanto, a primeira solução, por exemplo, seria:
(que basicamente espera por qualquer caractere fora do intervalo ASCII hexadecimal: de \ x00 a \ x7F)
No Mountain Lion que não funciona (devido à falta de suporte do PCRE no BSD grep) , mas com o
pcre
instalado via Homebrew, o seguinte também funciona:Quaisquer prós ou contras que alguém possa pensar?
fonte
LC_COLLATE=C grep $'[^\1-\177]'
obras (para arquivos sem nula bytes)O seguinte funciona para mim:
Caracteres não ASCII iniciam em 0x80 e vão para 0xFF ao olhar para bytes. O Grep (e a família) não executam o processamento Unicode para mesclar caracteres de vários bytes em uma única entidade para a correspondência de expressões regulares como você deseja. A
-P
opção no meu grep permite o uso de\xdd
escapes nas classes de caracteres para realizar o que você deseja.fonte
echo '소녀시대' | grep -P "[\x80-\xFF]"
não retorna nada para mim - mais alguém pode confirmar? (GNU grep 2.21)echo '소녀시대' | grep -P "[^\x00-\x7F]"
. Ou simplesmente usarthe_silver_searcher
como fora apontado por @slf:echo '소녀시대' | ag "[\x80-\xFF]"
Em perl
fonte
perl -lne 'print if /[^[:ascii:]]/' file.xml
A maneira mais fácil é definir um caractere não ASCII ... como um caractere que não é um caractere ASCII.
Adicione uma guia após o
^
se necessário.A configuração
LC_COLLATE=C
evita surpresas desagradáveis sobre o significado dos intervalos de caracteres em muitos locais. A configuraçãoLC_CTYPE=C
é necessária para corresponder caracteres de byte único - caso contrário, o comando perderia seqüências de bytes inválidas na codificação atual. A configuraçãoLC_ALL=C
evita completamente os efeitos dependentes da localidade.fonte
echo "A" | LC_COLLATE=C grep '[^ -~]'
retorna uma partidaLC_ALL=en_US.UTF-8
, isso supera aLC_COLLATE
configuração. Você não deve ter isso em seu ambiente!LC_ALL
é apenas forçar uma tarefa específica a usar um código de idioma específico, geralmenteC
. Para definir o código do idioma padrão para todas as categorias, definaLANG
.LC_ALL=C
, ele se comporta de maneira diferente no Mac OS X e no Ubuntu. Depois de adicionar essa configuração, eles dão o mesmo resultado.Aqui está outra variante que achei que produziu resultados completamente diferentes da pesquisa grep
[\x80-\xFF]
na resposta aceita. Talvez seja útil para alguém encontrar caracteres não-ascii adicionais:grep --color='auto' -P -n "[^[:ascii:]]" myfile.txt
Nota: o grep do meu computador (um Mac) não tinha
-P
opção, então eu fizbrew install grep
e iniciei a chamada acima com emggrep
vez degrep
.fonte
O código a seguir funciona:
Substitua
/tmp
pelo nome do diretório que você deseja pesquisar.fonte
Procurando caracteres não imprimíveis. TLDR; Sumário executivo
LC_ALL=C
necessária para fazer o grep fazer o que você poderia esperar com o Unicode estendidoSO os localizadores de char não-ASCII preferidos:
como na resposta principal, o grep inverso:
como na resposta principal, mas COM
LC_ALL=C
:. . Mais . . detalhes excruciantes sobre isso:. . .
Eu concordo com Harvey acima, enterrado nos comentários, geralmente é mais útil procurar caracteres não imprimíveis OU é fácil pensar em não ASCII quando você realmente deveria estar pensando em não imprimível. Harvey sugere "use isto:"
[^\n -~]
". Adicione \ r para arquivos de texto do DOS. Isso se traduz em"[^\x0A\x020-\x07E]
"e adicione \ x0D para CR"Além disso, adicionar -c (mostrar número de padrões correspondentes) ao grep é útil ao procurar por caracteres não imprimíveis, pois as cadeias correspondentes podem atrapalhar o terminal.
Eu achei que adicionar intervalo 0-8 e 0x0e-0x1f (ao intervalo 0x80-0xff) é um padrão útil. Isso exclui o TAB, CR e LF e mais um ou dois caracteres imprimíveis incomuns. Portanto, o IMHO, um padrão grep bastante útil (embora bruto), é ESTE:
Na verdade, geralmente você precisará fazer isso:
demolir:
Por exemplo, exemplo prático de uso find para grep todos os arquivos no diretório atual:
Você pode ajustar o grep às vezes. por exemplo, caractere BS (0x08 - backspace) usado em alguns arquivos imprimíveis ou para excluir VT (0x0B - guia vertical). Os caracteres BEL (0x07) e ESC (0x1B) também podem ser considerados imprimíveis em alguns casos.
ATUALIZAÇÃO: Eu tive que revisitar isso recentemente. E, YYMV, dependendo das configurações do terminal / previsão do tempo solar, MAS. . Percebi que o grep não estava encontrando muitos caracteres unicode ou estendidos. Embora intuitivamente eles correspondam ao intervalo de 0x80 a 0xff, os caracteres unicode de 3 e 4 bytes não foram correspondidos. ??? Alguém pode explicar isso? SIM. O @frabjous perguntou e o @calandoa explicou que
LC_ALL=C
deve ser usado para definir o código do idioma para o comando fazer a correspondência grep.por exemplo, meu local
LC_ALL=
vaziogrep com
LC_ALL=
correspondências vazias caracteres codificados em 2 bytes, mas não em 3 e 4 bytes:grep with
LC_ALL=C
parece corresponder a todos os caracteres estendidos que você deseja:ESTA correspondência perl (parcialmente encontrada em outro lugar no stackoverflow) OU o grep inverso na resposta superior parecem encontrar TODOS os caracteres "estranhos" e ~ maravilhosos ~ "não-ascii" estranhos e sem definição de localidade:
SO os localizadores de char não-ASCII preferidos:
como na resposta principal, o grep inverso:
como na resposta principal, mas COM
LC_ALL=C
:fonte
Estranhamente, eu tive que fazer isso hoje! Acabei usando o Perl porque não consegui fazer o grep / egrep funcionar (mesmo no modo -P). Algo como:
Para caracteres unicode (como
\u2212
no exemplo abaixo), use o seguinte:fonte
Pode ser interessante saber como procurar um caractere unicode. Este comando pode ajudar. Você só precisa saber o código em UTF8
fonte
Encontrar todos os caracteres não-ascii dá a impressão de que alguém está procurando por seqüências unicode ou pretende extrair esses caracteres individualmente.
Para o primeiro, tente um destes (a variável
file
é usada para automação):O grep de baunilha não funciona corretamente sem LC_ALL = C, conforme observado nas respostas anteriores.
O intervalo ASCII é
x00-x7F
, o espaço éx20
, pois as cadeias possuem espaços que o intervalo negativo o omite.O intervalo não-ASCII é que
x80-xFF
, como as strings têm espaços, o intervalo positivo o adiciona.Presume-se que a sequência tenha pelo menos 7 caracteres consecutivos dentro do intervalo.
{7,}
.Para saída legível por shell,
uchardet $file
retorna uma estimativa da codificação do arquivo que é passada para iconv para interpolação automática.fonte
uchardet
comando. Obrigado por esse aviso!