У меня есть символ 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
ПРИМЕЧАНИЯ:
В Raku вы можете с такой же легкостью выполнить сопоставление с именем Unicode, например
\c[RUNIC LETTER FEHU FEOH FE F]
, что даст те же результаты, что и сопоставление с\x[16A0]
указанным выше именем.В Raku вы можете с такой же легкостью сопоставлять символы Unicode
ᚠ
, например , что даст те же результаты, что и сопоставление с\x[16A0]
или\c[RUNIC LETTER FEHU FEOH FE F]
выше.В 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
€
Или, если использовать perl
use -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'
анализа оболочкой.