Python中去除重音符号并保留下划线。

4
我正在处理一个自然语言处理的任务,需要使用一个名为Yoruba的语言语料库。Yoruba是一种带有变音符号(重音)和下点符号的语言。例如,这是一个 Yoruba 字符串:"ọmọàbúròẹlẹ́wà",我需要删除重音并保留下点符号。
我尝试使用 Python 中的 unidecode 库,但它会将重音和下点符号一并删除。
import unidecode
ac_stng = "ọmọàbúròẹlẹ́wà"
unac_stng = unidecode.unidecode(ac_stng)

我希望输出结果为"ọmọaburoẹlẹwa"。但是,当我在Python中使用unidecode库时,我得到了"omoaburoelewa"


你可能需要自己编写这个逻辑,否则就无法区分不同类型的变音符号。 - jonrsharpe
2个回答

4
我会使用Unicode标准化来处理这个问题。
像带重音和点之类的字符是预组合Unicode字符。如果你将它们分解,就可以得到基本字符加上重音、点等组合字符。然后你就可以删除不需要的部分,重新组合字符串成为预组合字符。
你可以在Python中使用unicodedata.normalize来实现。具体来说,你需要使用“NFD”(规范分解形式)标准化形式。这将给你字符的规范分解形式。然后,要重新组合字符,你需要使用“NFC”(规范组合形式)。
我将向您展示我的意思。首先,让我们看一下您提供的示例文本中的各个代码点:
>>> from pprint import pprint
>>> import unicodedata
>>> text = 'ọmọàbúròẹlẹ́wà'
>>> pprint([unicodedata.name(c) for c in text])
['LATIN SMALL LETTER O WITH DOT BELOW',
 'LATIN SMALL LETTER M',
 'LATIN SMALL LETTER O WITH DOT BELOW',
 'LATIN SMALL LETTER A WITH GRAVE',
 'LATIN SMALL LETTER B',
 'LATIN SMALL LETTER U WITH ACUTE',
 'LATIN SMALL LETTER R',
 'LATIN SMALL LETTER O WITH GRAVE',
 'LATIN SMALL LETTER E WITH DOT BELOW',
 'LATIN SMALL LETTER L',
 'LATIN SMALL LETTER E WITH ACUTE',
 'COMBINING DOT BELOW',
 'LATIN SMALL LETTER W',
 'LATIN SMALL LETTER A WITH GRAVE']

正如您所看到的,其中一个字符已经部分分解(具有单独的“带点下加符号”的字符)。现在让我们来看看完全分解的情况:

>>> text = unicodedata.normalize('NFD', text)
>>> pprint([unicodedata.name(c) for c in text])
['LATIN SMALL LETTER O',
 'COMBINING DOT BELOW',
 'LATIN SMALL LETTER M',
 'LATIN SMALL LETTER O',
 'COMBINING DOT BELOW',
 'LATIN SMALL LETTER A',
 'COMBINING GRAVE ACCENT',
 'LATIN SMALL LETTER B',
 'LATIN SMALL LETTER U',
 'COMBINING ACUTE ACCENT',
 'LATIN SMALL LETTER R',
 'LATIN SMALL LETTER O',
 'COMBINING GRAVE ACCENT',
 'LATIN SMALL LETTER E',
 'COMBINING DOT BELOW',
 'LATIN SMALL LETTER L',
 'LATIN SMALL LETTER E',
 'COMBINING DOT BELOW',
 'COMBINING ACUTE ACCENT',
 'LATIN SMALL LETTER W',
 'LATIN SMALL LETTER A',
 'COMBINING GRAVE ACCENT']

现在根据您的要求,看起来您想保留所有拉丁字母(可能还有ASCII的其他字符,我猜测),以及“COMBINING DOT BELOW”代码点,我们可以使用文字'\N{COMBINING DOT BELOW}'来引用它,使您的代码更易读。
这是一个示例函数,我认为它会实现您想要的功能:
import unicodedata

def remove_accents_but_not_dots(input_text):
    # Step 1: Decompose input_text into base letters and combinining characters
    decomposed_text = unicodedata.normalize('NFD', input_text)

    # Step 2: Filter out the combining characters we don't want
    filtered_text = ''
    for c in decomposed_text:
        if ord(c) <= 0x7f or c == '\N{COMBINING DOT BELOW}':
            # Only keep ASCII or "COMBINING DOT BELOW"
            filtered_text += c

    # Step 3: Re-compose the string into precomposed characters
    return unicodedata.normalize('NFC', filtered_text)

当然,在Python中字符串连接速度较慢,但我会将优化留给您。这个例子是为了可读性而编写的。
以下是结果的样子:
>>> remove_accents_but_not_dots('ọmọàbúròẹlẹ́wà')
'ọmọaburoẹlẹwa'

0

既然你想要进行特定类型的重音解析,那么最简单的方法可能是自己编写解析器。基本上,你可以使用ord()函数来检查字符串中每个字母的Unicode值,并将其与不希望出现重音的字母的Unicode值列表进行比较。我认为这有两个步骤:

首先,处理只有变音符号而没有点的字符。根据我从简单的研究中了解到的信息,对于给定的元音字母,它有三种可能的变音符号:尖音、重音和长音符号。然后,对于给定的元音字母,你可以创建一个包含每个变音符号变体的Unicode数字的数组。所以,对于字母"a",你会有以下结果:

a_diacritics = [224, 225, 257] # Unicode values for á, à, and ā

然后您可以比较输入中每个字母的Unicode值与该数组,如果匹配,则将其替换为普通的"a":
input_string = "ọmọàbúròẹlẹ́wà"
output = ""
for letter in input:
    if ord(letter) in a_diacritics:
        output += 'a'
    else:
        output += letter

运行这段代码后,变量output将等于"ọmọabúròẹlẹ́wa"。然后,您可以使用其他元音的Unicode值编写类似的数组和解析逻辑。

第二部分是带有变音符和点的字符。像“ẹ́”这样的字母通常在技术上是两个单独的字符。对于“ẹ́”,它是“é”和'combining dot below'字符,但对于外观相同的“ẹ́”,它是“ẹ”和'combining acute accent'字符。 对于带有额外点字符的字母,先前的数组步骤会处理它们。然后,对于添加的变音符字符,您可以有一个最终的Unicode值数组:

diacritic_marks = [769, 768, 772] # Unicode values for acute, grave, and macron diacritics

然后让解析循环忽略这些字符:

for letter in input_string:
    if ord(letter) in a_diacritics:
        output += 'a'
    elif ord(letter) in diacritic_marks:
        pass
    else:
        output += letter

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