我的“ uniq”或“ sort -u”行哪里去了,带有一些unicode字符


10

以下代码段中发生了什么?我没有得到预期的输出。

我认为这是一个错误,但是它发生在2个不同的程序(uniq和sort)上,所以我怀疑这与...有关,嗯,我不知道该怎么办。

前4个示例中的前3个有效,但第4个失败!

我希望所有字符都具有相同的行为。
即。打印出2行(从输入的3行)...但是在第4种情况下,我只有1行(对于sort -uuniq);两条相同的林消失了!

我已将输出'\ n'转换为空格以实现视图的紧凑性。

我正在使用uniq并从(GNU coreutils)7.4 排序 ...在Ubuntu 10.04.3 LTS桌面上运行。

剧本:

{
  locale -k LC_COLLATE
  echo
  for c1 in x 〼 ;do 
    for c2 in z 〇 ;do 
      echo -n "asis   : "; echo -e "$c1\n$c2\n$c2"          |tr '\n' ' ';echo
      echo -n "uniq   : "; echo -e "$c1\n$c2\n$c2" |uniq    |tr '\n' ' ';echo
      echo -n "sort -u: "; echo -e "$c1\n$c2\n$c2" |sort -u |tr '\n' ' ';echo
      echo
    done
    echo
  done
}

输出:

collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=2081
collate-codeset="UTF-8"

asis   : x z z 
uniq   : x z 
sort -u: x z 

asis   : x 〇 〇 
uniq   : x 〇 
sort -u: 〇 x 


asis   : 〼 z z 
uniq   : 〼 z 
sort -u: 〼 z 

asis   : 〼 〇 〇 
uniq   : 〼 
sort -u: 〼 

# In the last example (of 4) where did the '〇' go? .. U+3007 IDEOGRAPHIC NUMBER ZERO
#

请注意 ..为了使它很清楚。sort单独使用(不带-u选项)...不会吞噬字符。.进来了,出来了...但是,正如Gilles对具有相同规范值的“异国” unicode字符的解释所预期的那样,这些字符没有被排序,除了它们作为未排序的FIFO组输出到排序输出的“顶部” ...所以这里确实存在两个问题:1.字符没有被排序,就像“天真”一样“预期,以及2‘两者的独特’功能sortuniq数据丢失(在某些情况下)。
Peter.O 2011年

更新:正如Gilles所提到的(当特定于区域设置的排序不是必需的,并且字符顺序合适时),sort -u并且uniq可以很好地与以下命令配合使用:( LC_COLLATE=C; echo -e "〼\n〇\n〇" |sort -u|uniq
Peter.O 2011年

Answers:


11

简短版:归类在命令行实用工具中并不真正起作用。

较长的版本:比较两个字符串的基础函数是strcoll。该描述不是很有帮助,但是操作的概念性方法是将两个字符串都转换为规范形式,然后比较这两种规范形式。该函数strxfrm构造此规范形式。

让我们观察一些字符串的规范形式(使用GNU libc,在Debian挤压下):

$ export LC_ALL=en_US.UTF-8
$ perl -C255 -MPOSIX -le 'print "$_ ", unpack("h*", strxfrm($_)) foreach @ARGV' b a A à 〼 〇
b d010801020
a c010801020
A c010801090
à 101010102c6b
〼 101010102c6b102c6b102c6b
〇 101010102c6b102c6b102c6b

如您所见,〼和〇具有相同的规范形式。我认为这是因为在en_US.UTF-8语言环境的整理表中未提及这些字符。但是,它们存在于日语环境中。

$ export LC_ALL=ja_JP.UTF-8
$ perl -C255 -MPOSIX -le 'print "$_ ", unpack("h*", strxfrm($_)) foreach @ARGV' 〼 〇 
〼 303030
〇 3c9b

语言环境数据的源代码(以Debian压缩)在中/usr/share/i18n/locales/en_US,其中包括/usr/share/i18n/locales/iso14651_t1_common。该文件没有U3007或的条目U303C,也没有包含在我可以找到的任何范围内。

对构建排序规则的规则不熟悉,但是据我了解,相关的措辞是

未定义符号应解释为包括所有未明确指定或未通过省略号指定的编码字符集值。(…)如果未指定UNDEFINED符号,并且当前的编码字符集包含本节未指定的字符,则实用程序应发出警告消息并将此类字符放在字符整理顺序的末尾。

看来Glibc却忽略了未指定的字符。我不知道我对POSIX规范的理解是否存在缺陷,是否错过了Glibc的语言环境定义中的某些内容,或者Glibc的语言环境编译器中是否存在错误。


@Gilles:感谢您提供的翔实和详细的说明。.现在有一定道理,但我不知道如何“安全地”使用sort ..我不是在进行特别的“对语言环境敏感”的排序,所以任何粗略的排序会做...有快速解决方法吗?...,而我会逐渐理解这一点,但不会在“隔夜”发生.....例如,我的/ usr / share / i18n / charmaps / UTF-8包含对两个字符的引用,但采用UTF-8定义(?)似乎无济于事...哦,好了,没有什么神秘感的生活会是什么样。:) ...
Peter.O 2011年

1
@fred charmaps/UTF-8没有提及排序规则,这很locales/en_US重要。的第一条规则LC_COLLATE是:不要使用LC_COLLATE。在C(= POSIX)语言环境中,排序规则是合理的(严格基于数字字符值)。
吉尔(Gilles)“所以,别再邪恶了”,

2
分拣独特的方面做工精细前面时LC_COLLATE=C...谢谢...
Peter.O

1
并不是排序规则在实用程序中不起作用,而是glibc语言环境的设计不良。POSIX允许(目前,但是请参阅austingroupbugs.net/view.php?id=1070)该行为,但不幸的是,这种行为也是不可取的。
斯特凡Chazelas

6

要“安全地”使用sortUnicode字符串,可以看看msort

[...] Msort在选择键字段方面提供了更大的灵活性,更多的比较类型,在不同键上使用来自不同语言环境的归类规则的能力,在非西方数字系统中处理数字的能力以及缺少的其他多种选择在GNU排序和BSD排序中。而msort理解Unicode,而GNU排序和BSD排序则不能。[...]

http://www.billposer.org/Software/msort.html


@til:感谢您使我意识到msort。可选的GUI使介绍更容易些,以了解所提供的功能。能够复制生成的命令非常方便...是的,它确实对Unicode字符进行了排序, 但是(您不只是喜欢那些“ buts”:)...但是它没有唯一的选择: (...如您发布的链接中所述:Capabilities of GNU sort and BSD sort lacking in msort are the ability to merge files without sorting them (the --merge option) and the ability to emit only the first of an equal run (the --unique option)...尽管排序仍然有效:)
Peter.O 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.