如何用 unicode 值来 grep 字符?

如何用 unicode 值来 grep 字符?

我在文本文件中有 Unicode 字符 ᚠ,由其 Unicode 代码点 16A0 表示(该文本文件被编码(?)为 utf-8)。

当我这样做时,grep '\u16A0' test.txt我没有得到任何结果。我如何 grep 该字符?

答案1

您可以使用ANSI-C 引用由 shell 提供,用于替换 ANSI C 标准指定的反斜杠转义字符。这应该适用于任何命令,而不仅仅是grepBash 和 Zsh 等 shell 中的命令:

grep $'\u16A0'

对于一些更复杂的例子,你可以参考这个相关问题及其答案。

答案2

你可以使用乌格勒普作为 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 模式的匹配。

GitHub 上的 ugrep了解详情。

答案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
ᚠ ᚡ ᚢ ᚣ ᚤ ᚥ ᚦ ᚧ ᚨ ᚩ ᚪ ᚫ ᚬ ᚭ ᚮ ᚯ ᚰ ᚱ ᚲ ᚳ ᚴ ᚵ ᚶ ᚷ ᚸ ᚹ ᚺ ᚻ ᚼ ᚽ ᚾ ᚿ ᛀ ᛁ ᛂ ᛃ ᛄ ᛅ ᛆ ᛇ ᛈ ᛉ ᛊ ᛋ ᛌ ᛍ ᛎ ᛏ ᛐ ᛑ ᛒ ᛓ ᛔ ᛕ ᛖ ᛗ ᛘ ᛙ ᛚ ᛛ ᛜ ᛝ ᛞ ᛟ ᛠ ᛡ ᛢ ᛣ ᛤ ᛥ ᛦ ᛧ ᛨ ᛩ ᛪ ᛫ ᛬ ᛭ ᛮ ᛯ ᛰ

匹配字符,打印(空格分隔的)“word”:

~$ 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

使用perlpcre2grep或至少使用或可以使用 PCRE 或 PCRE2 的pcregrep任何实现,您可以使用来匹配具有值的字符(或仅用于值 <= 0xff)。grep\x{16A0}0x16A0\xe9

为了使该值成为 unicode 代码点,我们需要告诉他们输入必须从 UTF-8 解码。在 PCRE/PCRE2 中,这是通过(*UTF)在模式的开头使用(主要相当于传递PCRE_UTF给正则表达式引擎),尽管最新版本的 GNUgrep至少在使用 UTF-8 作为其字符映射的语言环境中调用时会自动执行此操作。对于pcregreppcre2grep,也可以使用 选项启用该-u功能(另请参见-Upcre2grep

在 中perl,这是通过环境变量-C的 (big char) 选项PERL_UNICODE。单独使用时-C,缩写是-CSDL如果语言环境像 GNU 一样使用 UTF-8,则解码/重新编码将输入/输出重新编码为 UTF-8 grep,或者-CSD无条件地执行此操作,或者使用模块等从任何编码显式解码Encode

在PCRE2(由GNU 或最新版本perl使用)中,您还可以使用.其 Unicode 名称为: .pcre2grepgrep\N{U+16A0}perl\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}'

要根据未以 UTF-8 编码的输入上的 Unicode 值匹配字符,这些字符将不起作用,因为它们只能在 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'

其他几个 shell 也从 zsh 复制了它$'\uHHHH',包括 ksh93、bash、mksh 和一些基于 ash 的 shell,但有一些不幸的差异:在 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 编码,因为在 shell 解析LC_CTYPE=en_GB.iso885915时尚未运行。$'\u20ac'

相关内容