(grep) Regex para corresponder a caracteres não ASCII?

169

No Linux, eu tenho um diretório com muitos arquivos. Alguns deles têm caracteres não ASCII, mas todos são UTF-8 válidos . Um programa possui um bug que o impede de trabalhar com nomes de arquivos não ASCII, e eu tenho que descobrir quantos são afetados. Eu faria isso com finde depois faria um grep para imprimir os caracteres não ASCII e, em seguida, faria um wc -lpara encontrar o número. Não precisa ser grep; Posso usar qualquer expressão regular padrão do Unix , como Perl , sed , AWK , etc.

No entanto, existe uma expressão regular para 'qualquer caractere que não seja um caractere ASCII'?

Rory
fonte
1
Paul, sim, eu posso usar perl
Rory
/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]
Tinmarino

Respostas:

310

Isso corresponderá a um único caractere não ASCII:

[^\x00-\x7F]

Este é um PCRE ( Expressão Regular Compatível com Perl) válido .

Você também pode usar as teclas abreviadas do POSIX :

  • [[:ascii:]] - corresponde a um único caractere ASCII
  • [^[:ascii:]] - corresponde a um único caractere não ASCII

[^[:print:]] provavelmente será suficiente para você. **

Alix Axel
fonte
3
@adrianm: Não, ^é válido no PCRE.
Alix Axel
10
Isso é exatamente correto. No entanto, você deve usar o pcregrep, não o grep padrão. [^ [: print:]] não funcionará se o seu terminal estiver configurado em UTF8.
Rory
@Rory, por :print:que não funciona em um terminal UTF8? Isso funciona para mim em um terminal UTF8:27.chr =~ /[^[:print:]]/
akostadinov 10/11/14
Isso é realmente bom para corrigir nomes de arquivos ruins - rename 's/[^\x00-\x7F]//g' *(você pode usar -npara verificar se os nomes mudam primeiro).
naught101
Como faço para corresponder qualquer caractere que não seja UTF8 e qualquer outro caractere específico?
precisa saber é o seguinte
37

Não, [^\x20-\x7E] não é ASCII.

Isso é real ASCII:

 [^\x00-\x7F]

Caso contrário, ele cortará novas linhas e outros caracteres especiais que fazem parte da tabela ASCII!

Peter L
fonte
3

[^\x00-\x7F]e [^[:ascii:]]perca alguns bytes de controle para que as strings possam ser a melhor opção às vezes. Por exemplo cat test.torrent | perl -pe 's/[^[:ascii:]]+/\n/g', fará coisas estranhas ao seu terminal, onde strings test.torrentse comportará.

user1133275
fonte
3

Para validar a caixa de texto, aceite ascii Use apenas este padrão

[\x00-\x7F]+

Othman Mahmoud
fonte
3

Eu uso [^\t\r\n\x20-\x7E]+e isso parece estar funcionando bem.

SolidSnakeUk89
fonte
2

Você pode usar este regex:

[^\w \xC0-\xFF]

Caso pergunte, as opções são Multiline .

CypherPotato
fonte
2

Você realmente não precisa de uma regex.

printf "%s\n" *[!\ -~]*

Isso também mostrará nomes de arquivos com caracteres de controle em seus nomes, mas considero isso um recurso.

Se você não tiver nenhum arquivo correspondente, o glob se expandirá para si mesmo, a menos que você tenha nullglobdefinido. (A expressão não corresponde a si mesma; portanto, tecnicamente, essa saída é inequívoca.)

triplo
fonte
Tardiamente, pode-se observar que este faz o trabalho corretamente se você realmente tem alguns arquivos que combinam com esse padrão. O comportamento em que o padrão é impresso quando não há correspondências é um pouco surpreendente, mas realmente correto. Eu editei a resposta para esclarecer isso.
Tripleee
1

Isso acabou sendo muito flexível e extensível. $ field = ~ s / [^ \ x00- \ x7F] // g; # portanto, todos os itens não ASCII ou específicos em questão podem ser limpos. Muito bom na seleção ou no pré-processamento de itens que eventualmente se tornarão chaves de hash.

Don Turnblade
fonte