如何通过在python中折叠来实现Unicode字符串匹配

u0b*_*6ae 10 python unicode

我有一个实现增量搜索的应用程序.我有一个匹配的unicode字符串目录,并将它们与给定的"key"字符串匹配; 如果目录字符串按顺序包含键中的所有字符,则它是"命中",如果目录字符串中的关键字符集群,则排序更好.

无论如何,这工作正常,并完全匹配的Unicode,让"OST"将匹配" OST blocket"或"R OST "或"R ö d ST恩".

无论如何,现在我想实现折叠,因为在某些情况下,区分诸如"á"或"é"的目录字符和关键字符"a"或"e"是没有用的.

例如:"Ole"应匹配"Olé"

我如何在Python中最好地实现这个unicode-folding matcher?效率非常重要,因为我必须将数千个目录字符串与短的给定键匹配.

它不必将其变成ascii; 实际上,算法的输出字符串可以是unicode.留下一个角色比剥离它更好.


我不知道接受哪个答案,因为我使用了两者兼而有之.采用NKFD分解并删除组合标记几乎可以完成,我只添加了一些自定义音译.这是现在看起来的模块:(警告,包含内联的unicode字符,因为编辑这种方式更好.)

# -*- encoding: UTF-8 -*-

import unicodedata
from unicodedata import normalize, category

def _folditems():
    _folding_table = {
        # general non-decomposing characters
        # FIXME: This is not complete
        u"?" : u"l",
        u"œ" : u"oe",
        u"ð" : u"d",
        u"þ" : u"th",
        u"ß" : u"ss",
        # germano-scandinavic canonical transliterations
        u"ü" : u"ue",
        u"å" : u"aa",
        u"ä" : u"ae",
        u"æ" : u"ae",
        u"ö" : u"oe",
        u"ø" : u"oe",
    }

    for c, rep in _folding_table.iteritems():
        yield (ord(c.upper()), rep.title())
        yield (ord(c), rep)

folding_table = dict(_folditems())

def tofolded(ustr):
    u"""Fold @ustr

    Return a unicode str where composed characters are replaced by
    their base, and extended latin characters are replaced by
    similar basic latin characters.

    >>> tofolded(u"Wy??cz")
    u'Wylacz'
    >>> tofolded(u"naïveté")
    u'naivete'

    Characters from other scripts are not transliterated.

    >>> tofolded(u"?????") == u'?????'
    True

    (These doctests pass, but should they fail, they fail hard)
    """
    srcstr = normalize("NFKD", ustr.translate(folding_table))
    return u"".join(c for c in srcstr if category(c) != 'Mn')

if __name__ == '__main__':
    import doctest
    doctest.testmod()
Run Code Online (Sandbox Code Playgroud)

(并且,对于实际匹配,如果任何人感兴趣:我事先为我的所有目录构造折叠字符串,并将折叠版本放入已经可用的目录对象别名属性中.)

Joã*_*lva 6

您可以使用 strip_accents功能删除重音:

def strip_accents(s):
   return ''.join((c for c in unicodedata.normalize('NFD', unicode(s)) if unicodedata.category(c) != 'Mn'))

>>> strip_accents(u'Östblocket')
'Ostblocket'
Run Code Online (Sandbox Code Playgroud)