Python 默认按字节值排序,这意味着 é 在 z 和其他同样有趣的东西之后。在 Python 中按字母顺序排序的最佳方法是什么?
有这方面的图书馆吗?我什么也找不到。最好排序应该有语言支持,所以它理解 åäö 应该在瑞典语中的 z 之后排序,但 ü 应该按 u 排序,等等。因此,Unicode 支持几乎是一个要求。
如果没有库,那么最好的方法是什么?只需将字母映射到整数值并将字符串映射到整数列表?
Python 默认按字节值排序,这意味着 é 在 z 和其他同样有趣的东西之后。在 Python 中按字母顺序排序的最佳方法是什么?
有这方面的图书馆吗?我什么也找不到。最好排序应该有语言支持,所以它理解 åäö 应该在瑞典语中的 z 之后排序,但 ü 应该按 u 排序,等等。因此,Unicode 支持几乎是一个要求。
如果没有库,那么最好的方法是什么?只需将字母映射到整数值并将字符串映射到整数列表?
IBM 的ICU库可以做到这一点(以及更多)。它具有 Python 绑定:PyICU。
更新:ICU 和 ICU 之间排序的核心区别在于 ICU在使用ISO 14651时使用locale.strcoll
完整的Unicode 排序算法。strcoll
此处简要总结了这两种算法之间的差异:http ://unicode.org/faq/collation.html#13 。这些是相当奇特的特殊情况,在实践中几乎不重要。
>>> import icu # pip install PyICU
>>> sorted(['a','b','c','ä'])
['a', 'b', 'c', 'ä']
>>> collator = icu.Collator.createInstance(icu.Locale('de_DE.UTF-8'))
>>> sorted(['a','b','c','ä'], key=collator.getSortKey)
['a', 'ä', 'b', 'c']
我在答案中看不到这一点。我的应用程序使用 python 的标准库根据语言环境进行排序。这很容易。
# 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)
向 Lennart 和其他回答者提出的问题:没有人知道“语言环境”还是不能胜任这项任务?
试试 James Tauber 的Python Unicode Collation Algorithm。它可能不会完全按照您的意愿行事,但似乎值得一看。有关这些问题的更多信息,请参阅Christopher Lenz 的这篇文章。
总结和扩展答案:
locale.strcoll
在 Python 2 下,locale.strxfrm
实际上会解决问题,并且做得很好,假设您安装了相关的语言环境。我也在 Windows 下对其进行了测试,其中语言环境名称令人困惑地不同,但另一方面,它似乎默认安装了所有支持的语言环境。
ICU
在实践中不一定能做得更好,但它做得更多。最值得注意的是,它支持拆分器,可以将不同语言的文本拆分为单词。这对于没有单词分隔符的语言非常有用。您需要有一个词库作为拆分的基础,因为这不包括在内。
它还具有语言环境的长名称,因此您可以获得漂亮的语言环境显示名称,支持公历以外的其他日历(尽管我不确定 Python 接口是否支持)以及大量其他或多或少晦涩难懂的语言环境支持.
总而言之:如果你想按字母顺序排序和依赖于语言环境,你可以使用该locale
模块,除非你有特殊要求,或者还需要更多依赖于语言环境的功能,比如分词器。
您可能还对pyuca感兴趣:
http://jtauber.com/blog/2006/01/27/python_unicode_collation_algorithm/
虽然这肯定不是最准确的方法,但它是一种非常简单的方法,至少可以让它有点正确。它还击败了 web 应用程序中的语言环境,因为语言环境不是线程安全的,并且会在整个进程范围内设置语言设置。它也比依赖外部 C 库的 PyICU 更容易设置。
我将脚本上传到 github,因为在撰写本文时原始脚本已关闭,我不得不求助于网络缓存来获取它:
https://github.com/href/Python-Unicode-Collation-Algorithm
我成功地使用这个脚本在 plone 模块中对德语/法语/意大利语文本进行了合理的排序。
我看到答案已经做得很好了,只是想指出Human Sort中的一个编码效率低下。要将选择性的逐字符转换应用于 unicode 字符串 s,它使用以下代码:
spec_dict = {'Å':'A', 'Ä':'A'}
def spec_order(s):
return ''.join([spec_dict.get(ch, ch) for ch in s])
Python 有一种更好、更快、更简洁的方式来执行这个辅助任务(在 Unicode 字符串上——字节字符串的类似方法有一个不同的并且有点不太有用的规范!-):
spec_dict = dict((ord(k), spec_dict[k]) for k in spec_dict)
def spec_order(s):
return s.translate(spec_dict)
您传递给该translate
方法的 dict 具有 Unicode 序数(不是字符串)作为键,这就是为什么我们需要从原始 char-to-char 进行重建步骤的原因spec_dict
。(您传递给翻译的 dict 中的值 [与键相反,键必须是序数] 可以是 Unicode 序数、任意 Unicode 字符串或 None 以删除相应的字符作为翻译的一部分,因此很容易指定“忽略一个某些用于排序目的的字符”、“将 ä 映射到 ae 以进行排序”等)。
在 Python 3 中,您可以更简单地获得“重建”步骤,例如:
spec_dict = ''.maketrans(spec_dict)
有关可以在 Python 3中使用此静态方法的其他方式,请参阅文档。maketrans
要实现它,您需要阅读有关“Unicode 排序算法”的信息,请参阅 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/
最简单、最简单、最直接的方法是调用 Perl 库模块Unicode::Collate::Locale,它是标准Unicode::Collate模块的子类。您需要做的就是向构造函数传递瑞典的语言环境值"xv"
。
(对于瑞典语文本,您可能不一定喜欢这一点,但由于 Perl 使用抽象字符,您可以使用任何您喜欢的 Unicode 代码点——无论平台或构建!很少有语言提供这样的便利。我提到它是因为我已经与最近在这个令人抓狂的问题上输给了 Java 很多。)
问题是我不知道如何从 Python 访问 Perl 模块——除了使用 shell 标注或双面管道。为此,我为您提供了一个名为ucsort的完整工作脚本,您可以调用它来轻松完成您所要求的工作。
此脚本 100% 符合完整的Unicode 排序算法,支持所有定制选项!!如果您安装了可选模块或运行 Perl 5.13 或更高版本,则您可以完全访问易于使用的 CLDR 语言环境。见下文。
想象一个以这种方式排序的输入集:
b o i j n l m å y e v s k h d f g t ö r x p z a ä c u q
按代码点的默认排序产生:
a b c d e f g h i j k l m n o p q r s t u v x y z ä å ö
每个人的书都是不正确的。使用我的脚本,它使用 Unicode 排序算法,你得到这个顺序:
% perl ucsort /tmp/swedish_alphabet | fmt
a å ä b c d e f g h i j k l m n o ö p q r s t u v x y z
这是默认的 UCA 排序。要获取瑞典语语言环境,请以这种方式调用ucsort:
% perl ucsort --locale=sv /tmp/swedish_alphabet | fmt
a b c d e f g h i j k l m n o p q r s t u v x y z å ä ö
这是一个更好的输入演示。一、输入集:
% fmt /tmp/swedish_set
cTD cDD Cöd Cbd cAD cCD cYD Cud cZD Cod cBD Cnd cQD cFD Ced Cfd cOD
cLD cXD Cid Cpd cID Cgd cVD cMD cÅD cGD Cqd Cäd cJD Cdd Ckd cÖD cÄD
Ctd Czd Cxd cHD cND cKD Cvd Chd Cyd cUD Cld Cmd cED Crd Cad Cåd Ccd
cRD cSD Csd Cjd cPD
按代码点,这样排序:
Cad Cbd Ccd Cdd Ced Cfd Cgd Chd Cid Cjd Ckd Cld Cmd Cnd Cod Cpd Cqd
Crd Csd Ctd Cud Cvd Cxd Cyd Czd Cäd Cåd Cöd cAD cBD cCD cDD cED cFD
cGD cHD cID cJD cKD cLD cMD cND cOD cPD cQD cRD cSD cTD cUD cVD cXD
cYD cZD cÄD cÅD cÖD
但是使用默认的 UCA 会以这种方式排序:
% ucsort /tmp/swedish_set | fmt
cAD Cad cÅD Cåd cÄD Cäd cBD Cbd cCD Ccd cDD Cdd cED Ced cFD Cfd cGD
Cgd cHD Chd cID Cid cJD Cjd cKD Ckd cLD Cld cMD Cmd cND Cnd cOD Cod
cÖD Cöd cPD Cpd cQD Cqd cRD Crd cSD Csd cTD Ctd cUD Cud cVD Cvd cXD
Cxd cYD Cyd cZD Czd
但在瑞典语言环境中,这样:
% ucsort --locale=sv /tmp/swedish_set | fmt
cAD Cad cBD Cbd cCD Ccd cDD Cdd cED Ced cFD Cfd cGD Cgd cHD Chd cID
Cid cJD Cjd cKD Ckd cLD Cld cMD Cmd cND Cnd cOD Cod cPD Cpd cQD Cqd
cRD Crd cSD Csd cTD Ctd cUD Cud cVD Cvd cXD Cxd cYD Cyd cZD Czd cÅD
Cåd cÄD Cäd cÖD Cöd
如果您喜欢大写在小写之前排序,请执行以下操作:
% ucsort --upper-before-lower --locale=sv /tmp/swedish_set | fmt
Cad cAD Cbd cBD Ccd cCD Cdd cDD Ced cED Cfd cFD Cgd cGD Chd cHD Cid
cID Cjd cJD Ckd cKD Cld cLD Cmd cMD Cnd cND Cod cOD Cpd cPD Cqd cQD
Crd cRD Csd cSD Ctd cTD Cud cUD Cvd cVD Cxd cXD Cyd cYD Czd cZD Cåd
cÅD Cäd cÄD Cöd cÖD
你可以用ucsort做很多其他的事情。例如,这里是如何对英文标题进行排序:
% 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
通常,您需要 Perl 5.10.1 或更高版本才能运行该脚本。对于语言环境支持,您必须安装可选的 CPAN 模块Unicode::Collate::Locale
。或者,您可以安装 Perl 5.13+ 的开发版本,其中标准包含该模块。
这是一个快速原型,所以ucsort大多没有(der)记录。但这是它在命令行上接受的开关/选项的概要:
# standard options
--help|?
--man|m
--debug|d
# collator constructor options
--backwards-levels=i
--collation-level|level|l=i
--katakana-before-hiragana
--normalization|n=s
--override-CJK=s
--override-Hangul=s
--preprocess|P=s
--upper-before-lower|u
--variable=s
# program specific options
--case-insensitive|insensitive|i
--input-encoding|e=s
--locale|L=s
--paragraph|p
--reverse-fields|last
--reverse-output|r
--right-to-left|reverse-input
是的,好的:这确实是我用于调用的参数列表Getopt::Long
,但你明白了。:)
如果你能弄清楚如何在不调用 Perl 脚本的情况下直接从 Python 调用 Perl 库模块,那么一定要这样做。我只是不知道自己怎么样。我很想学习如何。
同时,我相信这个脚本会做你需要做的所有事情——甚至更多! 我现在将它用于所有文本排序。它终于做了我很久很久以来需要的东西。
唯一的缺点是这个--locale
参数会导致性能下降,尽管它对于常规的非语言环境来说足够快,但仍然是 100% 符合 UCA的排序。由于它将所有内容加载到内存中,您可能不想在千兆字节文档上使用它。我每天使用它很多次,最后对文本进行合理的排序肯定很棒。
最近我一直在使用 zope.ucol ( https://pypi.python.org/pypi/zope.ucol ) 来完成这项任务。例如,对德语 ß 进行排序:
>>> import zope.ucol
>>> collator = zope.ucol.Collator("de-de")
>>> mylist = [u"a", u'x', u'\u00DF']
>>> print mylist
[u'a', u'x', u'\xdf']
>>> print sorted(mylist, key=collator.key)
[u'a', u'\xdf', u'x']
zope.ucol 还包含 ICU,因此可以替代 PyICU。
Jeff Atwood 写了一篇关于自然排序顺序的好帖子,其中他链接到一个脚本,该脚本几乎可以满足您的要求。
无论如何,这不是一个简单的脚本,但它确实有用。
对于您的用例,它远非一个完整的解决方案,但您可以查看effbot.org 的unaccent.py脚本。它的基本作用是从文本中删除所有重音符号。您可以使用“净化”文本按字母顺序排序。(有关更好的描述,请参阅此页面。)