我正在玩bash,体验utf-8编码。我是unicode的新手。 以下命令(以及它们的输出)让我感到惊讶:
$ locale
LANG = “fr_FR.UTF-8”
LC_COLLATE = “fr_FR.UTF-8”
LC_CTYPE = “fr_FR.UTF-8”
LC_MESSAGES = “fr_FR.UTF-8”
LC_MONETARY = “fr_FR.UTF-8”
LC_NUMERIC = “fr_FR.UTF-8”
LC_TIME = “fr_FR.UTF-8”
LC_ALL =
$ printf'1 \né\ n12 \ n123 \ n'| egrep'^(。| ...)$'
1
é
12个
$ touch1é12123
$ ls | egrep'^(。| ...)$'
1
123
确定。两个egrep过滤具有一个或三个字符的行。它们的输入非常相似,但输出与字符é不同。有什么解释吗?
有关我的环境的更多详情:
$ uname -a
Darwin macbook-pro-de-admin-6.local 10.4.0 Darwin Kernel Version 10.4.0:Fri Apr 23 18:28:53 PDT 2010; root:xnu-1504.7.4~1 / RELEASE_I386 i386
$ egrep -V
egrep(GNU grep)2.5.1版权所有1988,1992-1999,2000,2001自由软件基金会 这是免费软件;查看复制条件的来源。没有 保证;甚至不适用于适销性或特定用途的适用性。
答案 0 :(得分:2)
任何可变长度编码都会混淆不知道编码的工具,并在使用单字符通配符时考虑字节而不是字符(因为该工具假定byte =字符)。如果使用文字字符,那么对于UTF-8,它无关紧要,因为UTF-8的结构会阻止字符中间的匹配(假设编码正确)。
至少某些版本的grep应该是UTF-8识别的,根据http://mailman.uib.no/public/corpora/2006-December/003760.html,GNU grep 2.5.1及更高版本包含在那里,只要适当的LANG是组。但是,如果您使用旧版本或GNU grep以外的其他版本,则可能是您的问题的原因,因为é是一个双字节字符(0xC3 0xA9)。
编辑:根据你最近的评论,你的grep可能是支持Unicode的,但它不会执行任何类型的Unicode normalization(说实话,我真的没想到它。)
0x65 0xCC 0x81是e,后跟COMBINING ACUTE ACCENT (U+0301)。这实际上是两个字符,但由于组合字符的语义,它被渲染为一个字符。这会导致grep将其检测为两个字符;一个用于e,一个用于重音。
分解的Unicode似乎可能是文件名实际存储在文件系统中的方式 - 否则,您可以存储的文件出于所有意图和目的,具有完全相同的名称,但仅在组合使用方面有所不同字符。