更正 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+0900
到 U+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 进行的操作。
下面的输出是错误的。应该只返回 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+0900
到 U+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 进行的操作。