用ASCII等效字符替换特殊字符

50

有没有可以将特殊字符替换为ASCII等效字符的库,例如:

"Cześć"

收件人:

"Czesc"

我当然可以创建地图:

{'ś':'s', 'ć': 'c'}

我想使用一些替换函数,但是我不想在程序中硬编码所有的等价项,如果已经有某个函数可以做到这一点。


1
可能是Python中简单的ASCII URL编码的重复问题。 - miku
1
可能重复:https://dev59.com/03M_5IYBdhLWcg3waiiJ - Anurag Uniyal
寻找“Unihandecode”。 - n611x007
6个回答

48
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import unicodedata
text = u'Cześć'
print unicodedata.normalize('NFD', text).encode('ascii', 'ignore')

9
使用"NFKD"比使用"NFD"更经常地产生ASCII输出。 - dan04
8
它并不适用于所有情况,例如:(大众Polo)-点火如何检查助力泵是否工作?转换为(大众Polo)- Zapon如何检查助力泵是否工作? - Szymon Roziewski

23

你可以通过以下方式完成大部分工作:

import unicodedata

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

很遗憾,存在无法分解为ASCII字母+组合符号的带重音的拉丁字母,您必须手动处理它们。这些包括:

  • Æ → AE
  • Ð → D
  • Ø → O
  • Þ → TH
  • ß → ss
  • æ → ae
  • ð → d
  • ø → o
  • þ → th
  • Œ → OE
  • œ → oe
  • ƒ → f

23

对我来说,unidecode这个包是最好的选择:

from unidecode import unidecode
text = "Björn, Łukasz and Σωκράτης."
print(unidecode(text))
# ==> Bjorn, Lukasz and Sokrates.

您可能需要安装该软件包:

pip install unidecode

上述解决方案比对unicodedata.normalize()输出进行编码(和解码)的解决方案更加简单且更加健壮,这也是其他答案所建议的。
# This doesn't work as expected:
ret = unicodedata.normalize('NFKD', text).encode('ascii', 'ignore')
print(ret)
# ==> b'Bjorn, ukasz and .'
# Besides not supporting all characters, the returned value is a
# bytes object in python3. To yield a str type:
ret = ret.decode("utf8") # (not required in python2)

1
它将 "ß" 翻译为 "ss",但将 "ä" 翻译为 "a",而不是 "ae"。 - Robin Dinse
@RobinDinse 这是有意为之的,请参阅 unidecode 的文档以了解此背后的原因。在将字符串传递给 unidecode 之前,您始终可以自己替换三个分音符äöü。 - normanius

5

可以尝试使用trans软件包,这看起来非常有前途。支持波兰语。


这对我来说非常完美,而且它是BSD许可证。 - UltraNurd
对我来说也是完美的运行。 - admfotad

4
我是这样做的:
POLISH_CHARACTERS = {
    50309:'a',50311:'c',50329:'e',50562:'l',50564:'n',50099:'o',50587:'s',50618:'z',50620:'z',
    50308:'A',50310:'C',50328:'E',50561:'L',50563:'N',50067:'O',50586:'S',50617:'Z',50619:'Z',}

def encodePL(text):
    nrmtxt = unicodedata.normalize('NFC',text)
    i = 0
    ret_str = []
    while i < len(nrmtxt):
        if ord(text[i])>128: # non ASCII character
            fbyte = ord(text[i])
            sbyte = ord(text[i+1])
            lkey = (fbyte << 8) + sbyte
            ret_str.append(POLISH_CHARACTERS.get(lkey))
            i = i+1
        else: # pure ASCII character
            ret_str.append(text[i])
        i = i+1
    return ''.join(ret_str)

执行时:

encodePL(u'ąćęłńóśźż ĄĆĘŁŃÓŚŹŻ')

它将会产生如下输出:
u'acelnoszz ACELNOSZZ'

这对我来说很好用 - ;D

1

unicodedata.normalize 技巧最好描述为半 ASCII。这里有一个健壮的方法,其中包括一个字母没有分解的映射表。请注意注释中的额外映射条目。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接