首页 文章

如何在Python中按字母顺序对unicode字符串进行排序?

提问于
浏览
88

Python默认按字节值排序,这意味着é来自z和其他同样有趣的东西 . 在Python中按字母顺序排序的最佳方法是什么?

有这个图书馆吗?我找不到任何东西 . 最好排序应该有语言支持所以它理解åäö应该用瑞典语中的z排序,但是ü应该用u等排序 . 因此,Unicode支持是非常必要的 .

如果没有库,那么最好的方法是什么?只需从字母到整数值进行映射,然后将字符串映射到整数列表即可?

11 回答

  • 0

    IBM的ICU库就是这样做的(还有更多) . 它有Python绑定:PyICU .

    Update :ICU和 locale.strcoll 之间排序的核心差异是ICU使用完整Unicode Collation Algorithmstrcoll 使用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']
    
  • 9

    我在答案中没有看到这一点 . 我的应用程序使用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和其他回答者的问题:没有人知道'locale'或者不能完成这项任务吗?

  • 0

    试试James Tauber的Python Unicode Collation Algorithm . 它可能不会完全按照您的意愿完成,但似乎值得一看 . 有关这些问题的更多信息,请参阅Christopher Lenz的this post .

  • 7

    您可能也对 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模块中巧妙地对德语/法语/意大利语文本进行排序 .

  • 48

    摘要和扩展答案:

    在Python 2下 locale.strcolllocale.strxfrm 实际上会解决问题,并且做得很好,假设你安装了有问题的语言环境 . 我也在Windows下对它进行了测试,其中区域设置名称容易混淆,但另一方面,它似乎默认安装了所有支持的语言环境 .

    ICU 并不一定在实践中做得更好,但它确实做得更多 . 最值得注意的是,它支持分割器,可以将不同语言的文本分成单词 . 这对于那些不需要使用单词语料库作为拆分基础的语言非常有用,因为它不包括在内 .

    它还具有很长的语言环境名称,因此您可以获得该语言环境的漂亮显示名称,支持除Gregorian之外的其他日历(虽然我不确定Python界面是否支持)以及大量其他或多或少不明显的语言环境支持 .

    So all in all: 如果要按字母顺序和语言环境排序,可以使用 locale 模块,除非您有特殊要求,或者还需要更多与语言环境相关的功能,如单词分割器 .

  • 8

    我看到答案已经做得很好,只是想在Human Sort中指出一个编码效率低下 . 要将选择性char-by-char转换应用于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 方法的字典有Unicode序号(不是字符串)作为键,这就是我们需要从原始char-to-char spec_dict 重建步骤的原因 . (传递给翻译的dict中的值[而不是键,必须是序数]可以是Unicode序号,任意Unicode字符串或None,以删除相应的字符作为翻译的一部分,因此很容易指定"ignore a certain character for sorting purposes","map ä to ae for sorting purposes"等等) .

    在Python 3中,您可以更简单地获得“重建”步骤,例如:

    spec_dict = ''.maketrans(spec_dict)
    

    有关在Python 3中使用此 maketrans 静态方法的其他方法,请参阅the docs .

  • 1

    完整的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区域设置 . 见下文 .

    示范

    想象一下以这种方式排序的输入集:

    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执行许多其他操作 . 例如,以下是如何使用英语对 Headers 进行排序:

    % 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脚本,那么一定要这样做 . 我只是不知道自己 . 我很想学习如何 .

    与此同时,我相信这个脚本将完成您所需要的所有特定功能 - and more! 我现在将其用于所有文本排序 . 它终于完成了我需要的很长一段时间 .

    唯一的缺点是 --locale 参数导致性能下降,尽管它足够快,足以进行常规的非语言分析 . 由于它将所有内容加载到内存中,您可能不希望在千兆字节文档上使用它 . 我每天都会使用它很多次,而且最后确保它有很好的文本排序 .

  • 66
  • 2

    最近我一直在使用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 .

  • 1

    它远不是您的用例的完整解决方案,但您可以查看来自effbot.org的unaccent.py脚本 . 它基本上做的是删除文本中的所有重音 . 您可以使用该'sanitized'文本按字母顺序排序 . (有关更好的说明,请参阅this页 . )

  • 6

    杰夫阿特伍德写了一篇关于Natural Sort Order的好文章,在其中他链接到一个做pretty much what you ask的剧本 .

    无论如何,这不是一个微不足道的剧本,但它可以解决问题 .

相关问题