问题:如何在Python中按字母顺序对unicode字符串排序?
Python默认情况下按字节值排序,这意味着é在z和其他同样有趣的事情之后。在Python中按字母顺序排序的最佳方法是什么?
有图书馆吗?我什么都找不到。最好是排序应该有语言支持,因此它理解åäö应该用瑞典语在z之后排序,但是ü应该用u进行排序,依此类推。因此,Unicode支持非常必要。
如果没有它的库,什么是最好的方法?只需将字母映射到整数值,然后将字符串映射到整数列表?
回答 0
IBM的ICU库可以做到这一点(还有更多)。它具有Python绑定:PyICU。
更新:在ICU之间进行排序的核心区别locale.strcoll
在于,ICU使用完整的Unicode排序算法,而strcoll
使用ISO 14651。
此处简要总结了这两种算法之间的区别: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']
回答 1
我没有在答案中看到这一点。我的应用程序使用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和其他回答者的问题:没有人知道“语言环境”吗?还是不符合这项任务?
回答 2
尝试使用James Tauber的Python Unicode排序规则算法。它可能无法完全满足您的要求,但似乎值得一看。有关这些问题的更多信息,请参阅Christopher Lenz的这篇文章。
回答 3
您可能也对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模块中的德语/法语/意大利语文本进行了合理排序。
回答 4
摘要和扩展答案:
locale.strcoll
在Python 2下,并locale.strxfrm
假设您已经安装了有问题的语言环境,实际上可以解决问题,并且表现出色。我也在Windows下进行了测试,这在令人困惑的语言环境名称方面是不同的,但另一方面,默认情况下似乎安装了所有受支持的语言环境。
ICU
不一定在实践中会做得更好,但是会做得更多。最值得注意的是,它支持可将不同语言的文本拆分为单词的拆分器。这对于没有单词分隔符的语言非常有用。您需要有一个语料库来用作拆分的基础,因为虽然不包括在内。
它还具有较长的语言环境名称,因此您可以获得语言环境的漂亮显示名称,支持除Gregorian之外的其他日历(尽管我不确定Python接口是否支持该日历),以及成吨的其他或多或少晦涩的语言环境支持。
因此,总而言之:如果您希望按字母顺序和语言环境进行排序,则可以使用该locale
模块,除非您有特殊要求,或者还需要更多的语言环境相关功能,例如单词拆分器。
回答 5
我看到答案已经做了出色的工作,只想指出“ 人类排序”中的编码效率低下。要将选择性逐字符转换应用于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的dict中的值(相对于键,键必须为序数)可以是Unicode序数,任意Unicode字符串,也可以是None来删除相应字符作为翻译的一部分,因此很容易指定“忽略一个某些字符以进行排序”,“将ä映射到ae以进行排序”等)。
在Python 3中,您可以更简单地完成“重建”步骤,例如:
spec_dict = ''.maketrans(spec_dict)
请参阅的文档你可以使用这个其他方式maketrans
在Python 3静态方法。
回答 6
要实现它,您需要阅读有关“ 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/
回答 7
最近,我一直在使用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。
回答 8
完整的UCA解决方案
执行此操作的最简单,最简单,最直接的方法是对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大多没有记录。但这是它在命令行上接受的开关/选项的摘要:
# 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
,但是您明白了。:)
如果您可以弄清楚如何直接从Python调用Perl库模块而不调用Perl脚本,则一定要这样做。我只是不知道自己。我很想学习如何。
同时,我相信此脚本将完成您需要做的所有工作,甚至更多! 现在,我将其用于所有文本排序。它最后确实已经需要很长一段时间我。
唯一的缺点是,这种--locale
说法会导致性能下降,尽管它对于常规,非语言环境但仍100%符合UCA的排序足够快。由于它将所有内容加载到内存中,因此您可能不想在千兆字节的文档上使用它。我每天使用它很多次,并且可以确保最后一次理智的文本排序非常好。
回答 9
这是远从你的使用情况的完整解决方案,但你可以看看的unaccent.py从effbot.org脚本。它的主要作用是删除文本中的所有重音。您可以使用“经过消毒的”文本按字母顺序排序。(有关详细说明,请参阅此页面。)
回答 10
杰夫阿特伍德(Jeff Atwood)在“ 自然排序顺序”上写了一篇不错的文章,他链接到一个脚本,该脚本几乎可以完成您的要求。
无论如何,它都不是琐碎的脚本,但是可以解决问题。