Como fazer grep de caracteres com seu valor unicode?

Como fazer grep de caracteres com seu valor unicode?

Eu tenho o caractere Unicode ᚠ, representado por seu ponto de código Unicode 16A0, em um arquivo de texto (o arquivo de texto é codificado (?) como utf-8).

Quando faço isso grep '\u16A0' test.txtnão obtenho resultado. Como faço para grep esse personagem?

Responder1

Você pode usarCitação ANSI-Cfornecido pelo seu shell, para substituir caracteres de escape de barra invertida, conforme especificado pelo padrão ANSI C. Isso deve funcionar para qualquer comando, não apenas grep, em shells como Bash e Zsh:

grep $'\u16A0'

Para alguns exemplos mais complexos, você pode consultaresta questão relacionadae suas respostas.

Responder2

Você poderia usarugrepcomo um substituto imediato do grep para corresponder ao ponto de código Unicode U+16A0:

ugrep '\x{16A0}' test.txt

São necessárias as mesmas opções do grep, mas oferece muito mais recursos, como:

ugrep pesquisa entrada UTF-8/16/32 e outros formatos. A opção -Q permite pesquisar muitos outros formatos de arquivo, como ISO-8859-1 a 16, EBCDIC, páginas de código 437, 850, 858, 1250 a 1258, MacRoman e KIO8.

ugrep corresponde aos padrões Unicodepor padrão (desativado com a opção -U). A sintaxe do padrão de expressão regular é compatível com POSIX ERE estendida com sintaxe semelhante a PCRE. A opção -P também pode ser usada para correspondência Perl com padrões Unicode.

Verugrep no GitHubpara detalhes.

Responder3

UsandoRaku(anteriormente conhecido como Perl_6)

Entrada de amostra:

https://www.cogsci.ed.ac.uk/~richard/unicode-sample-3-2.html


Combine o caractere, imprima a linha:

~$ raku -ne '.put if m/ \x[16A0] /;'  file
ᚠ ᚡ ᚢ ᚣ ᚤ ᚥ ᚦ ᚧ ᚨ ᚩ ᚪ ᚫ ᚬ ᚭ ᚮ ᚯ ᚰ ᚱ ᚲ ᚳ ᚴ ᚵ ᚶ ᚷ ᚸ ᚹ ᚺ ᚻ ᚼ ᚽ ᚾ ᚿ ᛀ ᛁ ᛂ ᛃ ᛄ ᛅ ᛆ ᛇ ᛈ ᛉ ᛊ ᛋ ᛌ ᛍ ᛎ ᛏ ᛐ ᛑ ᛒ ᛓ ᛔ ᛕ ᛖ ᛗ ᛘ ᛙ ᛚ ᛛ ᛜ ᛝ ᛞ ᛟ ᛠ ᛡ ᛢ ᛣ ᛤ ᛥ ᛦ ᛧ ᛨ ᛩ ᛪ ᛫ ᛬ ᛭ ᛮ ᛯ ᛰ

#OR:

~$ raku -e  'lines.grep(/ \x[16A0] /).put;'  file
ᚠ ᚡ ᚢ ᚣ ᚤ ᚥ ᚦ ᚧ ᚨ ᚩ ᚪ ᚫ ᚬ ᚭ ᚮ ᚯ ᚰ ᚱ ᚲ ᚳ ᚴ ᚵ ᚶ ᚷ ᚸ ᚹ ᚺ ᚻ ᚼ ᚽ ᚾ ᚿ ᛀ ᛁ ᛂ ᛃ ᛄ ᛅ ᛆ ᛇ ᛈ ᛉ ᛊ ᛋ ᛌ ᛍ ᛎ ᛏ ᛐ ᛑ ᛒ ᛓ ᛔ ᛕ ᛖ ᛗ ᛘ ᛙ ᛚ ᛛ ᛜ ᛝ ᛞ ᛟ ᛠ ᛡ ᛢ ᛣ ᛤ ᛥ ᛦ ᛧ ᛨ ᛩ ᛪ ᛫ ᛬ ᛭ ᛮ ᛯ ᛰ

Combine o caractere, imprima a "palavra" (separada por espaços em branco):

~$ raku -ne 'for .words() { .put if m/ \x[16A0] / };'  file

#OR:

~$ raku -e  'words.grep(/ \x[16A0] /).put;'  file

Combine o caractere, imprima as correspondências (exatas):

~$ raku -e 'given slurp() { put m:g/  \x[16A0]  / };'   file

#OR:

~$ raku -e 'slurp.match(:global,/  \x[16A0]  /).put;'   file

Combine o personagem, conte as correspondências e imprima:

~$ raku -e 'given slurp() { put m:g/  \x[16A0]  /.Int };'   file
1

#OR:

~$ raku -e 'slurp.match(:global,/  \x[16A0]  /).elems.put;'   file
1 

NOTAS:

  1. No Raku, você pode facilmente corresponder a um nome Unicode como \c[RUNIC LETTER FEHU FEOH FE F], que fornece os mesmos resultados da correspondência \x[16A0]acima.

  2. No Raku, você pode facilmente combinar com um caractere Unicode como , o que fornece os mesmos resultados que a correspondência com \x[16A0]ou \c[RUNIC LETTER FEHU FEOH FE F]superior.

  3. No Raku, você pode usar variáveis ​​Unicode (bem como operadores Unicode). Então isso funciona:

~$ raku -e 'my $ᚠ = slurp.match(/  \x[16A0]  /); say $ᚠ.Str.raku;'   file
"ᚠ"

https://docs.raku.org/linguagem/regexes#Unicode_properties
https://docs.raku.org/linguagem/unicode
https://docs.raku.org
https://raku.org

Responder4

Com perl, pcre2grep, pcregrepou qualquer grepimplementação que use ou possa usar PCRE ou PCRE2 pelo menos, você pode usar \x{16A0}para combinar o caractere com valor 0x16A0(ou apenas \xe9para valores <= 0xff).

Para que esse valor seja o ponto de código Unicode, precisamos dizer a eles que a entrada deve ser decodificada em UTF-8. No PCRE/PCRE2, isso é usado (*UTF)no início do padrão (principalmente equivalente à passagem PCRE_UTFpara o mecanismo regexp), embora versões recentes do GNU greppelo menos façam isso automaticamente quando invocado em um local que usa UTF-8 como seu charmap. Com pcregrepe pcre2grep, isso também pode ser habilitado com a -uopção (ver também -Uem pcre2grep).

Em perl, isso é feito através da -Copção (big char) da PERL_UNICODEvariável de ambiente. Onde -Csozinho, a abreviação de -CSDLé decodificar/recodificar, recodificar entrada/saída como UTF-8 se o código do idioma usar UTF-8 como o GNU grepfaz, ou -CSDfazer isso incondicionalmente, ou decodificar explicitamente de qualquer codificação usando, por exemplo, o Encodemódulo.

No perlPCRE2 (usado por pcre2grepversões recentes do GNU grep), você também pode usar \N{U+16A0}. E em perlseu nome Unicode: \N{RUNIC LETTER FEHU FEOH FE F}.

Então:

perl -C -ne 'print if /\x{16A0}/'
perl -C -ne 'print if /\N{U+16A0}/'
perl -C -ne 'print if /\N{RUNIC LETTER FEHU FEOH FE F}/'
PERL_UNICODE=SD perl -ne 'print if /\x{16A0}/'
pcregrep -u '\x{16A0}'
pcregrep '(*UTF)\x{16A0}'
pcre2grep -u '\x{16A0}'
pcre2grep '(*UTF)\x{16A0}'
pcre2grep -U '\x{16A0}'
pcre2grep -u '\N{U+16A0}'
grep -P '\x{16A0}'

Para corresponder um caractere com base em seu valor Unicode em uma entrada que não está codificada em UTF-8, eles não funcionarão, pois funcionam apenas em UTF-8. Em conjuntos de caracteres de byte único, \xHHfuncionará no valor by (o ponto de código no conjunto de caracteres correspondente, não em Unicode).

Por exemplo, na en_GB.iso885915localidade, onde o sinal do Euro (U+20AC) está em 0xA4.

$ LC_ALL=en_GB.iso885915 luit
$ locale charmap
ISO-8859-15
$ printf %s € | od -An -vtx1
 a4
$ echo € | grep -P '\x{20ac}'
grep: character code point value in \x{} or \o{} is too large
$ echo € | grep -P '\N{U+20ac}'
grep: \N{U+dddd} is supported only in Unicode (UTF) mode
$ echo € | grep -P '(*UTF)\N{U+20ac}'
$ echo € | grep -P '\xA4'

Então as opções seriam converter o texto para UTF-8:

$ echo € | iconv -t utf-8 | LC_ALL=C.UTF-8 grep -P '\x{20ac}' | iconv -f utf-8

Ou se estiver usando perluse -Mopen=localeem vez de -Cdizer para decodificar/codificar a entrada/saída de acordo com o conjunto de caracteres do código do idioma, em vez de UTF-8:

$ echo € | perl -Mopen=locale -ne 'print if /\N{U+20ac}/'

Ou não faça nenhuma decodificação, mas corresponda ao valor do byte desse caractere na localidade.

Por exemplo, com GNU ou zsh ou versões recentes do bash printf:

$ locale charmap
ISO-8859-15
$ printf '\u20ac' | od -An -vtx1
 a4
$ echo € | grep -F -- "$(printf '\u20ac')"

No zsh, você também pode usar $'\u20ac'which irá expandir para a codificação do caractere na localidade atual no momento (e relatar um erro se não houver tal caractere nessa localidade).

$ echo € | grep -F -- $'\u20ac'

Vários outros shells copiaram isso $'\uHHHH'do zsh desde a inclusão do ksh93, bash, mksh e alguns shells baseados em ash, mas com algumas diferenças infelizes: no ksh, isso é expandido em UTF-8, independentemente do local, e com o bash, isso é expandido no locale no momento em que o código é lido, em oposição ao momento em que o código é executado, por exemplo, em bash:

LC_CTYPE=C.UTF-8
{
  LC_CTYPE=en_GB.iso885915
  printf '\xA4\n' | grep -F -- $'\u20ac'
}

Ou:

LC_CTYPE=C.UTF-8
euro() {
  grep -F -- $'\u20ac'
}
LC_CTYPE=en_GB.iso885915
printf '\xa4\n' | euro

Não funcionará porque, em ambos os casos, o $'\u20ac'é expandido para sua codificação UTF-8, pois LC_CTYPE=en_GB.iso885915não foi executado no momento em que $'\u20ac'foi analisado pelo shell.

informação relacionada