icu:​​根据 2 个不同的区域设置对字符串进行排序

sae*_*gnu 6 python sorting locale icu

您可能知道,某些(也许是大多数)语言中的字母顺序与 Unicode 中的字母顺序不同。这就是为什么我们可能想要使用icu.Collator排序,就像这个 Python 示例一样:

from icu import Collator, Locale
collator = Collator.createInstance(Locale("fa_IR.UTF-8"))
mylist.sort(key=collator.getSortKey)
Run Code Online (Sandbox Code Playgroud)

这非常适合波斯弦。但它也会将所有波斯语字符串排在所有 ASCII/英语字符串之前(这与 Unicode 排序相反)。

如果我们想在给定的语言环境之前对 ASCII 进行排序怎么办?

或者理想情况下,我想按 2 个或多个区域设置进行排序。(例如给 提供多个Locale参数Collator.createInstance

如果我们可以告诉collator.getSortKey其他语言环境返回空字节,那么我可以创建一个包含 2 个collator.getSortKey()结果的元组,例如:

from icu import Collator, Locale

collator1 = Collator.createInstance(Locale("en_US.UTF-8"))
collator2 = Collator.createInstance(Locale("fa_IR.UTF-8"))

def sortKey(s):
    return collator1.getSortKey(s), collator2.getSortKey(s)

mylist.sort(key=sortKey)
Run Code Online (Sandbox Code Playgroud)

但看起来getSortKey总是返回非空字节。

小智 2

回答这个问题有点晚了,但在这里供以后参考。

ICU 校对使用 CLDR 校对算法,该算法是 Unicode 校对算法的剪裁。默认排序规则称为根排序规则。不要考虑具有一组排序规则的区域设置,更多地考虑区域设置指定区域设置所需的排序规则与根排序规则之间的任何差异。CLDR 采用极简方法,您只需要包含基于根排序规则所需的最小差异集。

英语使用根语言环境。没有剪裁。另一方面,波斯语需要一些规则来覆盖根排序规则的某些方面。

正如问题所示,波斯语排序规则将阿拉伯字符排列在拉丁字符之前。在波斯语的排序规则集中有一条规则[reorder Arab]。您需要重写此规则。

有几种方法可以做到这一点:

  1. icu.RuleBasedCollator与波斯语的自定义规则一起使用。
  2. 创建标准波斯语排序规则,检索规则,删除重新排序指令,然后使用修改后的规则icu.RuleBasedCollator
  3. 使用 BCP-47 语言标签而不是区域设置标识符创建整理器实例

还有其他方法,但第三种是最简单的:

loc = Locale.forLanguageTag("fa-u-kr-latn-arab")
collator = Collator.createInstance(loc)
sorted(mylist, key=collator.getSortKey)
Run Code Online (Sandbox Code Playgroud)

这将重新排序波斯语排序规则,将拉丁字母放在阿拉伯字母之前,然后是其他所有内容。