# python2.5 code below
# corpus is our unicode() strings collection as a list
corpus = [u"Art", u"Älg", u"Ved", u"Wasa"]
import locale
# this reads the environment and inits the right locale
locale.setlocale(locale.LC_ALL, "")
# alternatively, (but it's bad to hardcode)
# locale.setlocale(locale.LC_ALL, "sv_SE.UTF-8")
corpus.sort(cmp=locale.strcoll)
# in python2.x, locale.strxfrm is broken and does not work for unicode strings
# in python3.x however:
# corpus.sort(key=locale.strxfrm)
spec_dict = dict((ord(k), spec_dict[k]) for k in spec_dict)
def spec_order(s):
return s.translate(spec_dict)
传递给 translate 方法的字典有Unicode序号(不是字符串)作为键,这就是我们需要从原始char-to-char spec_dict 重建步骤的原因 . (传递给翻译的dict中的值[而不是键,必须是序数]可以是Unicode序号,任意Unicode字符串或None,以删除相应的字符作为翻译的一部分,因此很容易指定"ignore a certain character for sorting purposes","map ä to ae for sorting purposes"等等) .
% ucsort --preprocess='s/^(an?|the)\s+//i' /tmp/titles
Anathem
The Book of Skulls
A Civil Campaign
The Claw of the Conciliator
The Demolished Man
Dune
An Early Dawn
The Faded Sun: Kesrith
The Fall of Hyperion
A Feast for Crows
Flowers for Algernon
The Forbidden Tower
Foundation and Empire
Foundation’s Edge
The Goblin Reservation
The High Crusade
Jack of Shadows
The Man in the High Castle
The Ringworld Engineers
The Robots of Dawn
A Storm of Swords
Stranger in a Strange Land
There Will Be Time
The White Dragon
11 回答
IBM的ICU库就是这样做的(还有更多) . 它有Python绑定:PyICU .
Update :ICU和
locale.strcoll
之间排序的核心差异是ICU使用完整Unicode Collation Algorithm而strcoll
使用ISO 14651 .这两个算法之间的差异简要总结如下:http://unicode.org/faq/collation.html#13 . 这些是相当奇特的特殊情况,在实践中应该很少 .
我在答案中没有看到这一点 . 我的应用程序使用python的标准库根据语言环境进行排序 . 这很容易 .
Lennart和其他回答者的问题:没有人知道'locale'或者不能完成这项任务吗?
试试James Tauber的Python Unicode Collation Algorithm . 它可能不会完全按照您的意愿完成,但似乎值得一看 . 有关这些问题的更多信息,请参阅Christopher Lenz的this post .
您可能也对 pyuca 感兴趣:
http://jtauber.com/blog/2006/01/27/python_unicode_collation_algorithm/
虽然它肯定不是最精确的方式,但它是一种非常简单的方法,至少可以让它有点正确 . 它还在webapp中击败语言环境,因为语言环境不是线程安全的,并在进程范围内设置语言设置 . 它比PyICU更容易设置,PyICU依赖于外部C库 .
我将脚本上传到github,因为在撰写本文时原文已经关闭了,我不得不使用Web缓存来获取它:
https://github.com/href/Python-Unicode-Collation-Algorithm
我成功地使用这个脚本在plone模块中巧妙地对德语/法语/意大利语文本进行排序 .
摘要和扩展答案:
在Python 2下
locale.strcoll
,locale.strxfrm
实际上会解决问题,并且做得很好,假设你安装了有问题的语言环境 . 我也在Windows下对它进行了测试,其中区域设置名称容易混淆,但另一方面,它似乎默认安装了所有支持的语言环境 .ICU
并不一定在实践中做得更好,但它确实做得更多 . 最值得注意的是,它支持分割器,可以将不同语言的文本分成单词 . 这对于那些不需要使用单词语料库作为拆分基础的语言非常有用,因为它不包括在内 .它还具有很长的语言环境名称,因此您可以获得该语言环境的漂亮显示名称,支持除Gregorian之外的其他日历(虽然我不确定Python界面是否支持)以及大量其他或多或少不明显的语言环境支持 .
So all in all: 如果要按字母顺序和语言环境排序,可以使用
locale
模块,除非您有特殊要求,或者还需要更多与语言环境相关的功能,如单词分割器 .我看到答案已经做得很好,只是想在Human Sort中指出一个编码效率低下 . 要将选择性char-by-char转换应用于unicode字符串s,它将使用以下代码:
Python有一个更好,更快,更简洁的方式来执行这个辅助任务(在Unicode字符串上 - 字节字符串的类似方法有一个不同的,有点不太有用的规范! - ):
传递给
translate
方法的字典有Unicode序号(不是字符串)作为键,这就是我们需要从原始char-to-charspec_dict
重建步骤的原因 . (传递给翻译的dict中的值[而不是键,必须是序数]可以是Unicode序号,任意Unicode字符串或None,以删除相应的字符作为翻译的一部分,因此很容易指定"ignore a certain character for sorting purposes","map ä to ae for sorting purposes"等等) .在Python 3中,您可以更简单地获得“重建”步骤,例如:
有关在Python 3中使用此
maketrans
静态方法的其他方法,请参阅the docs .完整的UCA解决方案
最简单,最简单,最直接的方法来做到这一点callout到Perl库模块,Unicode::Collate::Locale,它是标准Unicode::Collate模块的子类 . 您所需要做的就是为瑞典传递构造函数
"xv"
的语言环境值 .(您可能不一定非常欣赏瑞典语文本,但因为Perl使用抽象字符,您可以使用任何Unicode代码点 - 无论是平台还是构建!很少有语言提供这样的便利 . 我提到它因为我打了一个最近在这个令人抓狂的问题上与Java失去了很多战斗 . )
问题是我不知道如何从Python访问Perl模块 - 除此之外,即使用shell标注或双面管道 . 为此,I have therefore provided you with a complete working script called ucsort,你可以打电话,完全轻松地完成你所要求的 .
This script is 100% compliant with the full Unicode Collation Algorithm ,支持所有剪裁选项!如果您安装了可选模块或运行Perl 5.13或更高版本,则您可以完全访问易于使用的CLDR区域设置 . 见下文 .
示范
想象一下以这种方式排序的输入集:
按代码点的默认排序产生:
每个人的书都不正确 . 使用我的脚本,它使用Unicode归类算法,你得到这个顺序:
这是默认的UCA排序 . 要获取瑞典语语言环境,请以这种方式调用ucsort:
这是一个更好的输入演示 . 首先,输入集:
按代码点,这样排序:
但是使用默认的UCA会使它按照这种方式排序:
但在瑞典语语言环境中,这种方式:
如果您希望大写字母在小写之前排序,请执行以下操作:
自定义排序
您可以使用ucsort执行许多其他操作 . 例如,以下是如何使用英语对 Headers 进行排序:
一般来说,运行脚本需要Perl 5.10.1或更高版本 . 对于区域设置支持,您必须安装可选的CPAN模块
Unicode::Collate::Locale
. 或者,您可以安装Perl,5.13的开发版本,其中包括该模块的标准版本 .呼叫约定
这是一个快速原型,因此ucsort主要是未记录的 . 但这是它在命令行上接受的开关/选项的概要:
是的,好的:那就是我用来调用
Getopt::Long
的参数列表,但是你明白了 . :)如果您可以直接从Python调用Perl库模块而无需调用Perl脚本,那么一定要这样做 . 我只是不知道自己 . 我很想学习如何 .
与此同时,我相信这个脚本将完成您所需要的所有特定功能 - and more! 我现在将其用于所有文本排序 . 它终于完成了我需要的很长一段时间 .
唯一的缺点是
--locale
参数导致性能下降,尽管它足够快,足以进行常规的非语言分析 . 由于它将所有内容加载到内存中,您可能不希望在千兆字节文档上使用它 . 我每天都会使用它很多次,而且最后确保它有很好的文本排序 .要实现它,您需要阅读"Unicode collation algorithm"请参阅http://en.wikipedia.org/wiki/Unicode_collation_algorithm
http://www.unicode.org/unicode/reports/tr10/
这里有一个示例实现
http://jtauber.com/blog/2006/01/27/python_unicode_collation_algorithm/
最近我一直在使用zope.ucol(https://pypi.python.org/pypi/zope.ucol)完成这项任务 . 例如,排序德国ß:
zope.ucol也包装了ICU,因此可以替代PyICU .
它远不是您的用例的完整解决方案,但您可以查看来自effbot.org的unaccent.py脚本 . 它基本上做的是删除文本中的所有重音 . 您可以使用该'sanitized'文本按字母顺序排序 . (有关更好的说明,请参阅this页 . )
杰夫阿特伍德写了一篇关于Natural Sort Order的好文章,在其中他链接到一个做pretty much what you ask的剧本 .
无论如何,这不是一个微不足道的剧本,但它可以解决问题 .