将非7位ASCII字母翻译为ASCII(如ń转n,ą转a)

9 投票
1 回答
2356 浏览
提问于 2025-04-17 10:40

我在找一种快速且方便的方法,用Python 3把包含非ASCII字母的字符串转换成只有ASCII字母的单词。

举几个例子!

żółw => zolw

móżdżek => mozdzek

łódź => lodz

等等……

很多国家的字母可以转换成ASCII字母(比如ń可以变成n)。我可以手动为我的语言(波兰语)指定每个字母的转换方式。但有没有什么自动化的方法来做到这一点?或者有没有什么库可以满足我的需求?

Python的str.encode()方法不行,因为"żółw".encode('ascii', 'replace') == "???w",而"żółw".encode('ascii', 'ignore') == "w"……

我可以为波兰字母做这样的转换,但我不想为其他语言也这样做:

>>> utf8_letters = ['ą','ę','ć','ź','ż','ó','ł','ń','ś']
>>> ascii_letters = ['a','e','c','z','z','o','l','n','s']
>>> trans_dict = dict(zip(utf8_letters,ascii_letters))
>>> turtle = "żółw"
>>> out = []
>>> for l in turtle:
...   out.append(trans_dict[l] if l in trans_dict else l)
>>> result = ''.join(out)
>>> result
'zolw'

上面的代码可以处理波兰字母,但看起来太丑了 :< 有没有更好的方法?

当然,这样的转换会改变一些单词的意思,但这没关系。

1 个回答

7

unicodedata模块可以用来处理这个问题。它有一些函数可以操作Unicode字符的名称,比如namelookup

现在我们来仔细看看这些函数。

name('Ż') == 'LATIN CAPITAL LETTER Z WITH DOT ABOVE'
name('ł') == 'LATIN SMALL LETTER L WITH STROKE'
lookup('LATIN CAPITAL LETTER Z') == 'Z'
lookup('LATIN SMALL LETTER L') == 'l'

你发现了什么规律吗?我们来写一个利用这个规律的函数:

import unicodedata

def normalize_char(c):
    try:
        cname = unicodedata.name(c)
        cname = cname[:cname.index(' WITH')]
        return unicodedata.lookup(cname)
    except (ValueError, KeyError):
        return c

normalize_char('ę') == 'e'
normalize_char('Ę') == 'E'
normalize_char('ś') == 's'

这个函数会在字符名称中查找单词WITH,然后去掉它后面的所有内容,再把结果传给lookup函数。
如果没有找到WITH,就会抛出ValueError错误;如果没有找到对应的字符,就会抛出KeyError错误,这样函数就会返回原来的字符。

接下来是一个基于之前函数的“翻译”字符串的函数:

def normalize(s):
    return ''.join(normalize_char(c) for c in s)

normalize('Móżdżek') == 'Mozdzek'

所以这个解决方案显然是很不错的,但我会把之前的方案留在下面。


unicodedata模块还有一个函数也能得到类似的结果——normalize,使用'NFKD'参数(兼容性分解),但它会漏掉大部分字符。


如果你有字符数据,你提供的代码可以进一步改进。

letters={'ł':'l', 'ą':'a', 'ń':'n', 'ć':'c', 'ó':'o', 'ę':'e', 'ś':'s', 'ź':'z', 'ż':'z'}
trans=str.maketrans(letters)
result=text.translate(trans)

这里有一个很好的字符数据表。这是JavaScript格式,但可以很容易地用于Python。


如果你不介意使用外部库,可以试试Unidecode。这个库就是为这个目的而创建的。

撰写回答