代码之家  ›  专栏  ›  技术社区  ›  u0b34a0f6ae

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

  •  9
  • u0b34a0f6ae  · 技术社区  · 17 年前

    我有一个实现增量搜索的应用程序。我有一个要匹配的unicode字符串目录,并将它们与给定的“键”字符串匹配;如果目录字符串按顺序包含键中的所有字符,则它是一个“命中”,如果键字符在目录字符串中聚集,则它的排名会更好。

    无论如何,这很好用,并且与unicode完全匹配,因此“st”将匹配 圣 圣 或“r” D 圣 嗯。

    例如:“Ole”应与“Ol”匹配

    如何在Python中最好地实现这个unicode折叠匹配器?效率很重要,因为我必须将数千个目录字符串与短的给定键相匹配。

    它不必将其转换为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()
    

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

    5 回复  |  直到 17 年前
        1
  •  7
  •   Community Mohan Dere    9 年前

    this 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'
    
        2
  •  4
  •   Community Mohan Dere    9 年前

    对于我的申请,我已经在另一条评论中提到了这一点:我想要一个 结果及 保留未处理的字符 原封不动。

    我将在中演示如何使用Perl实现这一点 this answer

        3
  •  1
  •   stefanw    17 年前
        4
  •  1
  •   Alan Plum    16 年前

    unidecode模块是一种通用解决方案(特别是用于搜索规范化和生成slug):

    http://pypi.python.org/pypi/Unidecode

    这可能是一个好主意,简单地剥离所有您不想在最终输出中使用的字符,或者用填充符替换它们(例如。 "äßœ$" "assoe$" § => SS € EU )您需要清理输入:

    input_str = u'äßœ$'
    input_str = u''.join([ch if ch.isalnum() else u'-' for ch in input_str])
    input_str = str(unidecode(input_str)).lower()
    

        5
  •  1
  •   Esteban Feldman    16 年前

    这个怎么样:

    normalize('NFKD', unicode_string).encode('ASCII', 'ignore').lower()
    

    从这里拍摄(西班牙语) http://python.org.ar/pyar/Recetario/NormalizarCaracteresUnicode