更正 Devnagari unicode 文本的区域设置

correct locale setting for devnagari unicode text

下面的输出是错误的。应该只返回 1 个单词而不是 2

$ echo 'उद्योजकता' |  grep -o -E '\w+'
उद
योजकता

有人告诉我这是由于区域设置造成的。我已经在 2 个不同的服务器上用 2 个不同的 O/S 检查了它,结果是一样的。

Ubuntu

$ locale
LANG=C.UTF-8
LANGUAGE=
LC_CTYPE="C.UTF-8"
LC_NUMERIC="C.UTF-8"
LC_TIME="C.UTF-8"
LC_COLLATE="C.UTF-8"
LC_MONETARY="C.UTF-8"
LC_MESSAGES="C.UTF-8"
LC_PAPER="C.UTF-8"
LC_NAME="C.UTF-8"
LC_ADDRESS="C.UTF-8"
LC_TELEPHONE="C.UTF-8"
LC_MEASUREMENT="C.UTF-8"
LC_IDENTIFICATION="C.UTF-8"
LC_ALL=

AWS EC2

# locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

我不确定应该选择哪个区域设置才能使 Devnagari unicode 文本仅在 space 处中断。

grep 的 macOS (11.2.3) 手册页底部有这条注释:

 BUGS
 The grep utility does not normalize Unicode input, so a pattern containing composed characters will not match decomposed input, and vice versa.

如果您对 Devnagari 文本的单独解决方案感到满意,这些将有所帮助。根据 wikipedia,Unicode 范围是 U+0900U+097f。所以,如果你的 shell 支持 $'...' 形式,你可以使用:

$ echo 'उद्योजकता' | grep -oE  $'[\u0900-\u097f]+'
उद्योजकता

如果 PCRE 可用:

$ echo 'उद्योजकता' | grep -oP '[\x{900}-\x{97f}]+'
उद्योजकता

使用 ripgrep 以获得更好的 Unicode 支持。

$ echo 'उद्योजकता' | rg -o '\w+'
उद्योजकता

编辑添加: 如果您机器上的 grep 支持与 Perl 兼容的正则表达式 (PCRE),则您可以使用类似的东西。这应该是这种情况,例如在亚马逊 Linux.

echo 'उद्योजकता' |grep -o -P '[\w\pL\pM]+'

这将匹配“word”字符或“Letter”代码点或“Mark”代码点,

echo 'उद्योजकता' |grep -o -P '(*UCP)[\w\pM]+'

这将启用 unicode 字符 属性 (UCP) 匹配,以便 \w 匹配所有字母和数字,无论脚本如何,但您仍必须在模式中包含 \pM 因为\w 根本不匹配 grep 中的“标记”点——它们不是字母数字代码点。

以上注意事项!我不知道 Devanagari 脚本,所以我不知道将所有此类“标记”字符视为您的目的的单词的一部分是否合适。可能是 \Mn(对于非间距标记)之类的较窄集合更适合您的需要,或者可能只有几个特定点要包含在这种情况下您需要 select他们在你的模式中。


在过去,\w 就意味着 [A-Za-z0-9_]。它以 ASCII 和 C 代码为导向。今天,在典型的解释中,它仍然表示“字母数字和下划线”,这可能因语言环境而异。

您说输出“错误”,但恐怕“错误”取决于您使用的正则表达式引擎。所以即使你使用的是“grep”,问题是哪个grep,在哪个OS,等等,等等

据我所知,您的输入包含 0x094d,根据 unicode 字符定义(至少,不是根据上面的 link)。这是一个“标记”。

一个 Unicode“文档”(推荐),其中包括引擎如何将“\w”定义为 Unicode-smart,实际上 it suggests to include Mark codepoints比赛。所以从这个意义上说,你的期望是自然的。但是,您可以从相同的 link 中看到,没有办法同时做到这一点并且同时严格符合 POSIX,这是许多正则表达式引擎想要做的。

Wikipedia indicates 有一些引擎支持 Unicode 属性 定义,但一般来说,grep 不会这样做。我对这些引擎(ruby 等)不够熟悉,无法准确说明您应该如何在命令行上尝试使用 grep 进行的操作。