我有一个应用程序实现增量搜索。我有一个Unicode字符串目录需要匹配并将它们与给定的“键”字符串匹配;如果目录字符串包含了所有按照顺序的键中的字符,它是一个“命中”,如果键字符在目录字符串中聚集,则排名更高。
无论如何,这个应用程序可以完美地匹配Unicode,并且"öst"会匹配"Östblocket"或"röst"或"röd sten" 。
现在我想要实现折叠(Folding),因为有些情况下,区分目录字符(例如“á”或“é”)和键字符(例如“a”或“e”)是没有用处的。
例如:"Ole" 应该匹配 "Olé"。
我该如何最好地在Python中实现这个Unicode-folding匹配器?效率很重要,因为我需要将数千个目录字符串与短的给定键匹配。
它不必将其转换为ASCII;事实上,算法的输出字符串可以是Unicode。保留字符比去除字符更好。
无论如何,这个应用程序可以完美地匹配Unicode,并且"öst"会匹配"Östblocket"或"röst"或"röd sten" 。
现在我想要实现折叠(Folding),因为有些情况下,区分目录字符(例如“á”或“é”)和键字符(例如“a”或“e”)是没有用处的。
例如:"Ole" 应该匹配 "Olé"。
我该如何最好地在Python中实现这个Unicode-folding匹配器?效率很重要,因为我需要将数千个目录字符串与短的给定键匹配。
它不必将其转换为ASCII;事实上,算法的输出字符串可以是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()
(如果有人感兴趣,实际匹配的方法是:我预先为我的所有目录构建了折叠字符串,并将折叠版本放入已经可用的目录对象别名属性中。)