![如何 grep 查找一系列 unicode 字符?](https://linux22.com/image/208691/%E5%A6%82%E4%BD%95%20grep%20%E6%9F%A5%E6%89%BE%E4%B8%80%E7%B3%BB%E5%88%97%20unicode%20%E5%AD%97%E7%AC%A6%EF%BC%9F.png)
如何 grep 查找一系列 unicode 字符?
我见过一个角色的例子。如何用 unicode 值来 grep 字符?
我对 shell 替换方法以外的方法感兴趣
因为 shell 替换似乎有点有限,例如它似乎不适用于非图形 unicode 字符,例如 \u80 的代码点。
我可以让该方法在一定范围内工作,但仅限于一定程度,因为它不会覆盖像 \u80 (unicode codepoint 80) 这样的非图形字符
$ echo grep [$'\u41'-$'\u45']
grep [A-E]
$ echo 4142434445|xxd -r -p
ABCDE
$ echo 4142434445|xxd -r -p | grep [$'\u41'-$'\u45']
ABCDE
$ 方法在 shell 级别使用替换,因此无法工作,例如从\u0080-\uFFFF
或\u0080
向上查找字符,因为如果 shell 无法显示字符,则它将无法工作。
ugrep 可通过 debian 的 apt-get 获得,但不适用于我在 VPS 上的 ubuntu 版本。我还得再测试一下。
笔记 事实证明,shell 替换方法确实适用于控制字符,因此甚至适用于一系列控制字符或任何 unicode 字符,毫无疑问, ugrep 也适用。最初,当我尝试使用 grep 进行 shell 替换时,我不知不觉地输入了错误的字节。例如echo 418042| xxd -r -p
显示,A▒B
所以我认为这很好用,我正在尝试 grep 。所以我将错误的数据传递给 grep 。 80 不是 \u80 的 utf-8。高位字符的回显(例如 £)清楚地表明它正在输出 utf-8。echo £ | xxd -p
显示c2a30a
£ 的 c2a3 是 utf-8。当我输入正确的字节时,它可以工作,例如c280
\u80 甚至 echo $'\u80'
可以工作。此页面适合显示 utf-8 到 unicode 代码点的映射。https://www.utf8-chartable.de/
虽然 shell 替换确实有效,但我很高兴我有一个答案,它可以执行 shell 替换之外的方法,因为有一个替代方案是好的。
答案1
在 gnu-grep 和类似中,您可以使用 PCRE 选项-P
并使用
\x{HHHH}
语法
$ grep -o -P '[\x{0410}-\x{042F}]+' # same as: grep -o -P '[А-Я]+'
абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕ
=> АБВГДЕ
答案2
在 GNU 系统上设置LC_COLLATE
为C
至少应保证顺序基于字符映射为多字节的语言环境中的 Unicode 代码点(例如 UTF-8、GB18030),以及其他方式的字节值(在使用 ASCII 或 ISO 的语言环境中) -8859-1 还应该匹配 unicode 代码点顺序)。
所以:
LC_COLLATE=C grep $'[\u1111-\uaaaa]'
应该找到至少包含一个字符的行,其 unicode 代码点介于 U+1111 和 U+AAAA 之间(根据设置指示的区域设置的字符映射进行编码LC_CTYPE
)。假设$LC_ALL
没有另外设置(因为它优先于$LC_COLLATE
)。
我建议避免跨越无效的 U+D800 - U+DFFF 范围。该范围内的代码点保留用于 UTF-16 编码,不适用于有效字符,并且已被某些工具用于对无效字符进行编码。使用 U+0001 和 U+D7FF 以及 U+E000 和 U+10FFFF 内的字符。
您还需要确保范围的边界与您所在区域中的有效字符相对应。的行为$'\uxxxx'
(其中 U+xxxx 不是区域设置字符集中的字符)在支持该$'\u...'
运算符的 shell 之间有所不同。在某些 shell 中(包括来自 zsh 的 ksh93 $'...'
)$'\u...'
,$'\u...'
仅适用于使用 UTF-8 作为字符映射的语言环境(请参阅 的输出locale charmap
)。
答案3
我采访了一些 Perl 专家。并获得了与 grep 等价的 perl oneliner 来查找一系列 unicode 字符。
$ echo £
£
所以就有了序数的概念,它是字符的数字表示。 (我想无论某物是编码还是代码点。序数这个词对于描述 \x 之后的内容很有用,根据选项,可以是编码,因此存储字节,或者可以是 unicode 代码点,字节但未编码用于存储/写入内存)
它以字节/八位位组为单位。可以用各种基地来表示。
%v
是 printf 的格式说明符,
$ perl -e 'printf "%vx\n",A'
41
$ perl -e 'printf "%vx\n",4'
34
%vd 将为 52(字符“4”的十进制数字表示。%vx 是十六进制表示
£ 的 UTF-8 编码为 c2a3 https://www.utf8-chartable.de/
$ echo £ | xxd -p
c2a30a
当使用超过两位数的 \x 时,必须使用花括号。 \X{..}
$ echo £ | perl -CIO -ne 'print if /[\x0A]/'
£
$ echo £ | perl -CIO -ne 'print if /[\x{0080}-\x{FFFF}]/'
£
-CIO 将序数从 UTF-8 表示形式 (c2a3) 转换为 unicode 代码点表示形式 (a3)。因此,当将 -CIO 与 \x 一起使用时,\x 后面的内容应该是 unicode 代码点表示
下面的内容可以将其与 \u0080 及以上的任何内容相匹配。不停止于\uFFFF。只是一个正则表达式的东西。
$ echo £ | perl -CIO -ne 'print if /[^\x00-\x7f]/'
£
如果删除 -CIO 那么您将匹配 UTF-8 字节,而不是 unicode 代码点字节。因为如果没有 -CI,它就不会将 UTF-8 编码字节转换/解释/解码为 unicode 代码点。
$ echo £ | perl -ne 'print if /\xc2/'
£
$ echo £ | perl -ne 'print if /\xa3/'
£
所以总结一下
$ echo £ | perl -CIO -ne 'print if /[\x{0080}-\x{FFFF}]/'
£
$ echo £ | perl -CIO -ne 'print if /[^\x00-\x7f]/'
£
$ echo £ | perl -CIO -ne 'print if /[^\x{00}-\{x7f}]/'
£
$ echo £ | perl -CIO -ne 'print if /[^\x{0000}-\{x007f}]/'
£
记录perl -CIO
于 perldoc perlrun
-C [*number/list*]
The -C flag controls some of the Perl Unicode features.
...
I 1 STDIN is assumed to be in UTF-8
O 2 STDOUT will be in UTF-8
和 perldoc perlunicode 和 perldoc perlre 提到 \x{...}