Как выполнить grep символов по их значению в Unicode?

Как выполнить grep символов по их значению в Unicode?

У меня есть символ Unicode ᚠ, представленный его кодовой точкой Unicode 16A0, в текстовом файле (текстовый файл закодирован(?) как utf-8).

Когда я это делаю, grep '\u16A0' test.txtя не получаю результата. Как мне выполнить grep этого символа?

решение1

Вы можете использоватьANSI-C цитированиепредоставляемый вашей оболочкой, для замены символов, экранированных обратной косой чертой, как указано в стандарте ANSI C. Это должно работать для любой команды, а не только grep, в таких оболочках, как Bash и Zsh:

grep $'\u16A0'

Для более сложных примеров вы можете обратиться кэтот связанный вопроси его ответы.

решение2

Вы могли бы использоватьugrepв качестве замены grep для соответствия кодовой точке Unicode U+16A0:

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

Он использует те же параметры, что и grep, но предлагает гораздо больше возможностей, таких как:

ugrep ищет входные данные в формате UTF-8/16/32 и других форматах. Опция -Q позволяет выполнять поиск во многих других форматах файлов, таких как ISO-8859-1–16, EBCDIC, кодовые страницы 437, 850, 858, 1250–1258, MacRoman и KIO8.

ugrep соответствует шаблонам Unicodeпо умолчанию (отключено с опцией -U). Синтаксис шаблона регулярного выражения совместим с POSIX ERE, расширен синтаксисом, подобным PCRE. Опция -P также может использоваться для сопоставления Perl с шаблонами Unicode.

Видетьugrep на GitHubдля получения подробной информации.

решение3

С использованиемРаку(ранее известный как Perl_6)

Пример ввода:

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


Найдите символ и выведите строку:

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

#OR:

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

Сопоставьте символ, выведите «слово» (разделенное пробелами):

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

#OR:

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

Сопоставьте символ, выведите (точные) совпадения:

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

#OR:

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

Сопоставьте символ, подсчитайте совпадения и выведите:

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

#OR:

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

ПРИМЕЧАНИЯ:

  1. В Raku вы можете с такой же легкостью выполнить сопоставление с именем Unicode, например \c[RUNIC LETTER FEHU FEOH FE F], что даст те же результаты, что и сопоставление с \x[16A0]указанным выше именем.

  2. В Raku вы можете с такой же легкостью сопоставлять символы Unicode , например , что даст те же результаты, что и сопоставление с \x[16A0]или \c[RUNIC LETTER FEHU FEOH FE F]выше.

  3. В Raku вы можете использовать переменные Unicode (а также операторы Unicode). Так что это работает:

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

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

решение4

С помощью perl, pcre2grep, pcregrepили любой другой grepреализации, которая использует или может использовать как минимум PCRE или PCRE2, вы можете использовать \x{16A0}для сопоставления символа со значением 0x16A0(или только \xe9для значений <= 0xff).

Чтобы это значение было кодовой точкой Unicode, нам нужно сообщить им, что входные данные должны быть декодированы из UTF-8. В PCRE/PCRE2 это делается с помощью (*UTF)в начале шаблона (в основном эквивалентно передаче PCRE_UTFв движок регулярных выражений), хотя последние версии GNU grepпо крайней мере делают это автоматически при вызове в локали, которая использует UTF-8 в качестве своей карты символов. С pcregrepи pcre2grepэто также можно включить с помощью -uопции (см. также -Uв pcre2grep).

В perl, это через -Cопцию (big char) переменной окружения PERL_UNICODE. Где -Cотдельно, сокращение от -CSDLозначает декодировать/перекодировать перекодировать ввод/вывод как UTF-8, если локаль использует UTF-8, как grepэто делает GNU, или с , -CSDчтобы сделать это безусловно, или явно декодировать из любой кодировки, используя, например, Encodeмодуль.

В perlи PCRE2 (как используется в pcre2grepпоследних версиях GNU grep) вы также можете использовать \N{U+16A0}. А в perlего имени в Unicode: \N{RUNIC LETTER FEHU FEOH FE F}.

Так:

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}'

Чтобы сопоставить символ на основе его значения Unicode на входе, который не закодирован в UTF-8, они не будут работать, поскольку они работают только в UTF-8. В однобайтовых кодировках будут \xHHработать по значению (кодовая точка в соответствующем кодировке, а не в Unicode).

Например, в en_GB.iso885915локали, где знак евро (U+20AC) находится в положении 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'

Таким образом, можно преобразовать текст в UTF-8:

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

Или, если использовать perluse -Mopen=localeвместо , -Cчтобы указать ему декодировать/кодировать ввод/вывод в соответствии с кодировкой локали, а не как UTF-8:

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

Или не выполнять никакого декодирования, а сопоставить байтовое значение этого символа в локали.

Например, с GNU или zsh или последними версиями bash printf:

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

В zsh вы также можете использовать $'\u20ac'which, который расширится до кодировки символа в текущей локали на данный момент (и сообщит об ошибке, если такого символа в этой локали нет).

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

С тех пор несколько других оболочек скопировали это $'\uHHHH'из zsh, включая ksh93, bash, mksh и несколько оболочек на основе ash, но с некоторыми досадными различиями: в ksh это раскрывается в UTF-8 независимо от локали, а в bash это раскрывается в локали во время чтения кода, а не во время его выполнения, например, в bash:

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

Или:

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

Не сработает, поскольку в обоих случаях $'\u20ac'расширяется до кодировки UTF-8, поскольку LC_CTYPE=en_GB.iso885915не был запущен к моменту $'\u20ac'анализа оболочкой.

Связанный контент