如何在Python中仅删除重音符号,而不是变音符号?

3

我正在使用以下代码

import unicodedata
def strip_accents(s):
    return ''.join(c for c in unicodedata.normalize('NFD', s)
              if unicodedata.category(c) != 'Mn')
strip_accents('ewaláièÜÖ')

这个函数返回

'ewalaieUO'

但我希望你能返回它
'ewalaieÜÖ'

有没有比使用str.replace(char_a,char_b)更简单的方法?如何高效地处理这个问题?

1个回答

3

那么让我们从您的测试输入开始:


In [1]: test
Out[1]: 'ewaláièÜÖ'

看看在规范化时它发生了什么:

In [2]: [x for x in unicodedata.normalize('NFD', test)]
Out[2]: ['e', 'w', 'a', 'l', 'a', '́', 'i', 'e', '̀', 'U', '̈', 'O', '̈']

以下是每个规范化元素的unicode数据类别:

In [3]: [unicodedata.category(x) for x in unicodedata.normalize('NFD', test)]
Out[3]: ['Ll', 'Ll', 'Ll', 'Ll', 'Ll', 'Mn', 'Ll', 'Ll', 'Mn', 'Lu', 'Mn', 'Lu', 'Mn']

正如您所看到的,不仅“accents”,而且“umlauts”都属于类别Mn。因此,您可以使用 unicodedata.name 替代 unicodedata.category

In [4]: [unicodedata.name(x) for x in unicodedata.normalize('NFD', test)]
Out[4]: ['LATIN SMALL LETTER E',
 'LATIN SMALL LETTER W',
 'LATIN SMALL LETTER A',
 'LATIN SMALL LETTER L',
 'LATIN SMALL LETTER A',
 'COMBINING ACUTE ACCENT',
 'LATIN SMALL LETTER I',
 'LATIN SMALL LETTER E',
 'COMBINING GRAVE ACCENT',
 'LATIN CAPITAL LETTER U',
 'COMBINING DIAERESIS',
 'LATIN CAPITAL LETTER O',
 'COMBINING DIAERESIS']

这里的重音名称是COMBINING ACUTE/GRAVE ACCENT,而"umlauts"名称是COMBINING DIAERESIS。因此,这是我的建议,如何修复你的代码:
def strip_accents(s):
    return ''.join(c for c in unicodedata.normalize('NFD', s)
              if not unicodedata.name(c).endswith('ACCENT')) 

strip_accents(test)
'ewalaieÜÖ'

同时,正如你可以从unicodedata文档中了解到的那样,这个模块只是一个包装器,用于数据库可在这里找到,因此请查看来自该数据库的名称列表以确保它涵盖了您需要的所有情况。


对于那些对Java 11+解决方案感兴趣的人,我提出了以下方法:Normalizer.normalize(s, Normalizer.Form.NFKD).replaceAll("((?<![aouAOU])\\p{M})|((?<=[aouAOU])[\\p{M}&&[^\u0308]])", "")。首先,将Unicode规范化为分解形式,以将次要字符(如重音符号)与主要字符(如"a")分离开来。然后,我们删除所有未在[aouAOU]之前的次要字符,以及除\u0308(组合分音符)之外的所有次要字符。可以使用Normalizer.normalize(s, Normalizer.Form.NFKC)重新组合结果。 - user27772

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