Unicode字符默认排序规则表

时间:2013-05-29 15:23:45

标签: postgresql unicode collation rhel

我不知道这个问题究竟属于哪个网站,所以请在此处发布。

我在RHEL 6.4上使用Postgresql 9.2并观察以下内容:

select foo 
from unnest('{а,ә,б,в,г,д,е,ж}'::text[]) as foo 
order by foo collate "kk_KZ.utf8"

给出

а
ә
б
в
г
д
е
ж

BUT

select foo 
from unnest('{а,ә,б,в,г,д,е,ж}'::text[]) as foo 
order by foo collate "en_US.utf8"

给出

а
б
в
г
д
е
ә -- misplaced
ж

此外,我发现有默认的Unicode排序规则元素表[1],它按正确的顺序列出了有问题的字符(04D9; [。199D.0020.0002.04D9]#CYRILLIC SMALL LETTER SCHWA)。

我理解,期望通过“en_US.utf8”语言环境正确处理西里尔字符是愚蠢的,但在字符通常不属于语言的情况下,Unicode或任何其他相关标准的正确行为是什么? / locale用于整理?

[1] http://www.unicode.org/Public/UCA/latest/allkeys.txt

3 个答案:

答案 0 :(得分:2)

这不是错位的。它可能对你而言,但它不适合我。 :-)严肃地说,Unicode没有正确的行为;根本就不可能。字符集是映射;排序规则是一组特定于语言环境的规则,用于对该组中的字符进行排序 - 即使在同一语言环境中也可以有多个排序规则。

ICU博士提供了丰富的例子,说明这种东西是多么棘手,以防你好奇。引用广泛:

http://userguide.icu-project.org/collation

  

[H]是语言在排序字符串中的一些方式:

     

字母A-Z可以按与英语不同的顺序排序。例如,在立陶宛语中,“y”在“i”和“k”之间排序。

     

可以将字母组合视为一个字母。例如,在传统的西班牙语中,“ch”被视为单个字母,并在“c”和“d”之间排序。

     

重音字母可视为非重音字母的次要变体。例如,“é”可以被视为等同于“e”。

     

重音字母可视为不同的字母。例如,丹麦语中的“Å”被视为一个单独的字母,在“Z”之后排序。

     

在一种语言中被认为是不同的非重音字母可能在另一种语言中不明显。例如,根据英语,字母“v”和“w”是两个不同的字母。但是,“v”和“w”被认为是瑞典语中同一字母的变体形式。

     

可以将信件视为两个字母。例如,在传统的德语中,“ä”被比作好像是“ae”。

     

泰语要求撤销某些字母的顺序。

     

法语要求在字符串末尾用重音符号排序的字母要在字符串开头的重音符号之前排序。例如,“côte”这个词在“coté”之前排序,因为最后“e”的尖锐重音比“o”上的旋律更重要。

     

有时小写字母排在大写字母之前。在其他情况下需要相反。例如,小写字母通常在英文大写字母之前排序。拉脱维亚字母恰恰相反。

     

即使使用相同的语言,不同的应用程序也可能需要不同的排序顺序。例如,在德语词典中,“öf”将出现在“of”之前。在电话簿中情况恰恰相反。

     

由于政府法规或Unicode中的新字符/脚本,排序顺序可能会随时间而变化。

答案 1 :(得分:2)

Unicode Collation Algorithm允许对DUCET进行任何定制。

没有“正确”的行为。人们可以期待各种各样的行为,最合适的取决于背景,观众。有时任何行为都可能是正确的,因为没有理由强制在美式英语校对中强制任何西里尔字母的订单。

Common Locale Data Repository为DUCET提供特定于语言环境的定制。 CLDR使用LDML(区域设置数据标记语言)来指定定制,语法由Unicode Technical Specification #35, part 5给出。

CLDR为en_US提供的最新版数据没有定制:它使用modified version of the DUCET(如“根目录”下的UTS#35中所述)。它列出了西里尔文A之后的西里尔语schwa,即你期望的顺序。

还有en_US_POSIX语言环境的数据,并且包含一些修改,但没有更改任何非ASCII语言。

系统中安装的en_US语言环境似乎使用剪裁将schwa放在E旁边可能是因为它们的形式相似。有人认为,对美国英语观众的惊喜会比A之后排序schwa更少:问问人们是什么,看看有多少人会告诉你这是一个“颠倒的E”。这不是对或错,但如果你问我,它似乎比CLDR中的校对更合适。

答案 2 :(得分:1)

Postgresql使用操作系统提供的语言环境。在您的设置中,语言环境由glibc提供。 Glibc使用ISO 14651的“古老”版本的大量修改版本(请参阅glibc Bug 14095 - Review / update collation data from Unicode / ISO 14651以获取有关尝试更新glibc语言环境数据时当前痛苦的信息)。

从glibc 2.28开始,将于2018-08-01发布,glibc将使用ISO 14651:2016中的数据(与Unicode 9同步),并将给出OP期望en_US的订单。

ISO 14651是用于比较字符串的方法和通用模板可定制排序的描述,它与UCA类似,但有一些差异。 CTT(通用模板表)是DUCET的ISO14651等价物,它们是对齐的。

第一次出现在glibc中的排序规则表中CYRILLIC SMALL LETTER SCHWA用于az_AZ区域设置(阿塞拜疆),在CYRILLIC SMALL LETTER IE之后排序。commit fcababc4e18fee81940dab20f7c40b1e1fb67209 Author: Ulrich Drepper <drepper@redhat.com> Date: Fri Aug 3 08:42:28 2001 +0000 Update. 2001-08-03 Ulrich Drepper <drepper@redhat.com> * locale/iso-639.def: Add Tigrinya. 这对应于:

iso14651_t1

从那里开始,该排序最终按照Bug 672 - Include iso14651_t1 in collation rules移动到文件commit 5d2489928c0040d2a71dd0e63c801f2cf98e7efc Author: Ulrich Drepper <drepper@redhat.com> Date: Sun Feb 18 04:34:28 2007 +0000 [BZ #672] 2005-01-16 Denis Barbier <barbier@linuxfr.org> [BZ #672] * locales/ca_ES: Replace current collation rules by including iso14651_t1 and adding extra rules if needed. There should be no noticeable changes in sorted text. only ligatures and ignoreable characters have modified weights. * locales/da_DK: Likewise. * locales/en_CA: Likewise. * locales/es_US: Likewise. * locales/fi_FI: Likewise. * locales/nb_NO: Likewise. [BZ #672] * locales/iso14651_t1: Simplified. Extended. ,这是为了简化glibc语言环境数据。这对应于:

en_US

glibc中的大多数语言环境都是从iso14651_t1开始,并定制它,这是你在for (const string & recipe : tokens){ //each recipe in recipe vector for (const string & ingredient : ingredientlist) // each ingredient in ingredient vector { int ingredientsfound = 0; // keep a count of the number of ingredients found. if (recipe.find(ingredient) != recipe.npos) // found ingredient in recipe { ingredientsfound++; } } if (ingredientsfound == ingredientlist.size()) { // found all of the ingredients cout << "yo"; } } 看到的。

虽然glibc基于阿塞拜疆的默认排序,但DUCET的基础是哈萨克斯坦和鞑靼的排序,这是差异的来源。