我在 Python 中有一个 Unicode 字符串,我想删除所有重音符号(变音符号)。

我在网上发现了一种用 Java 实现此目的的优雅方法:

  1. 将 Unicode 字符串转换为其长规范化形式(对于字母和变音符号使用单独的字符)
  2. 删除所有 Unicode 类型为“变音符号”的字符。

我是否需要安装 pyICU 这样的库,或者仅使用 python 标准库就可以做到这一点?那么Python 3呢?

重要的提示:我想避免使用从重音字符到非重音字符的显式映射的代码。

有帮助吗?

解决方案

统一编码 是这个问题的正确答案。它将任何 unicode 字符串音译为最接近的 ascii 文本表示形式。

例子:

accented_string = u'Málaga'
# accented_string is of type 'unicode'
import unidecode
unaccented_string = unidecode.unidecode(accented_string)
# unaccented_string contains 'Malaga'and is of type 'str'

其他提示

这个怎么样:

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

这也适用于希腊字母:

>>> strip_accents(u"A \u00c0 \u0394 \u038E")
u'A A \u0394 \u03a5'
>>> 

字符类别 “Mn”代表 Nonspacing_Mark, ,这与 MiniQuark 的答案中的 unicodedata.combining 类似(我没有想到 unicodedata.combining,但它可能是更好的解决方案,因为它更明确)。

请记住,这些操作可能会显着改变文本的含义。重音、元音变音等不是“装饰”。

我刚刚在网上找到了这个答案:

import unicodedata

def remove_accents(input_str):
    nfkd_form = unicodedata.normalize('NFKD', input_str)
    only_ascii = nfkd_form.encode('ASCII', 'ignore')
    return only_ascii

它工作得很好(例如,对于法语),但我认为第二步(删除重音符号)可以比删除非 ASCII 字符更好地处理,因为这对于某些语言(例如希腊语)来说会失败。最好的解决方案可能是显式删除标记为变音符号的 unicode 字符。

编辑:这可以解决问题:

import unicodedata

def remove_accents(input_str):
    nfkd_form = unicodedata.normalize('NFKD', input_str)
    return u"".join([c for c in nfkd_form if not unicodedata.combining(c)])

unicodedata.combining(c) 如果该字符将返回 true c 可以与前面的字符组合,主要是如果它是变音符号。

编辑2: remove_accents 期望一个 统一码 字符串,而不是字节字符串。如果你有一个字节字符串,那么你必须将其解码为 un​​icode 字符串,如下所示:

encoding = "utf-8" # or iso-8859-15, or cp1252, or whatever encoding you use
byte_string = b"café"  # or simply "café" before python 3.
unicode_string = byte_string.decode(encoding)

实际上,我正在开发兼容 python 2.6、2.7 和 3.4 的项目,并且我必须从免费用户条目创建 ID。

感谢您,我创建了这个神奇的功能。

import re
import unicodedata

def strip_accents(text):
    """
    Strip accents from input String.

    :param text: The input string.
    :type text: String.

    :returns: The processed String.
    :rtype: String.
    """
    try:
        text = unicode(text, 'utf-8')
    except (TypeError, NameError): # unicode is a default on python 3 
        pass
    text = unicodedata.normalize('NFD', text)
    text = text.encode('ascii', 'ignore')
    text = text.decode("utf-8")
    return str(text)

def text_to_id(text):
    """
    Convert input text to id.

    :param text: The input string.
    :type text: String.

    :returns: The processed String.
    :rtype: String.
    """
    text = strip_accents(text.lower())
    text = re.sub('[ ]+', '_', text)
    text = re.sub('[^0-9a-zA-Z_-]', '', text)
    return text

结果:

text_to_id("Montréal, über, 12.89, Mère, Françoise, noël, 889")
>>> 'montreal_uber_1289_mere_francoise_noel_889'

这不仅处理重音符号,还处理“笔画”(如 ø 等):

import unicodedata as ud

def rmdiacritics(char):
    '''
    Return the base character of char, by "removing" any
    diacritics like accents or curls and strokes and the like.
    '''
    desc = ud.name(unicode(char))
    cutoff = desc.find(' WITH ')
    if cutoff != -1:
        desc = desc[:cutoff]
    return ud.lookup(desc)

这是我能想到的最优雅的方式(亚历克西斯在本页的评论中提到过),尽管我认为它确实不是很优雅。

仍然有一些特殊字母无法由此处理,例如翻转字母和倒置字母,因为它们的 unicode 名称不包含“WITH”。无论如何,这取决于您想做什么。有时我需要去除重音来实现字典排序顺序。

回应@MiniQuark的回答:

我试图读取一个半法语(包含重音符号)的 csv 文件以及一些最终会变成整数和浮点数的字符串。作为测试,我创建了一个 test.txt 文件看起来像这样:

蒙特利尔, über, 12.89, Mère, Françoise, noël, 889

我必须包括行 23 让它工作(我在 python 票证中找到),并合并 @Jabba 的评论:

import sys 
reload(sys) 
sys.setdefaultencoding("utf-8")
import csv
import unicodedata

def remove_accents(input_str):
    nkfd_form = unicodedata.normalize('NFKD', unicode(input_str))
    return u"".join([c for c in nkfd_form if not unicodedata.combining(c)])

with open('test.txt') as f:
    read = csv.reader(f)
    for row in read:
        for element in row:
            print remove_accents(element)

结果:

Montreal
uber
12.89
Mere
Francoise
noel
889

(笔记:我使用的是 Mac OS X 10.8.4 并使用 Python 2.7.3)

gensim.utils.deaccent(文本)Gensim - 人类主题建模:

deaccent("Šéf chomutovských komunistů dostal poštou bílý prášek") 'Sef chomutovskych komunistu dostal postou bily prasek'

另一个解决方案是 统一编码.

并不是建议的解决方案 统一码数据 通常仅删除某些字符中的重音符号(例如事实证明 'ł' 进入 '', ,而不是进入 'l').

有些语言将变音符号组合为语言字母和重音变音符号来指定重音。

我认为明确指定要删除的变音符号更安全:

def strip_accents(string, accents=('COMBINING ACUTE ACCENT', 'COMBINING GRAVE ACCENT', 'COMBINING TILDE')):
    accents = set(map(unicodedata.lookup, accents))
    chars = [c for c in unicodedata.normalize('NFD', string) if c not in accents]
    return unicodedata.normalize('NFC', ''.join(chars))
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top