删除重音并保留 Python 中的点
Remove accents and keep under dots in Python
我正在处理一项 NLP 任务,该任务需要使用称为约鲁巴语的语言的语料库。约鲁巴语是一种在其字母表中有变音符号(口音)和下点的语言。例如,这是一个约鲁巴语字符串:"ọ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"
.
为此我会使用 Unicode normalization。
带有重音符和圆点的字符 precomposed Unicode characters. If you decompose them, you can get the base character plus the combining characters 用于重音符和圆点等等。然后你可以删除你不想要的那些并将字符串重新组合成预组合字符。
您可以在 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']
如您所见,其中一个字符已经部分分解(带有单独 "COMBINING DOT BELOW" 的字符)。现在让我们看看它完全分解:
>>> 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'
由于您想进行特定类型的重音解析,因此您自己编写解析器可能是最简单的方法。本质上,您可以使用 ord()
检查字符串中每个字母的 unicode 值,并对照 unicode 值列表检查是否有不希望有的重音字母。有两个步骤,我的看法是:
首先是处理只有变音符号,没有点号的字符。从我对这种语言的 admittedly cursory research 来看,似乎对于给定的元音,它具有三个可能的变音符号;急性、严重和长音符号。然后,对于给定的元音,您可以创建一个包含每个变音符号变体的 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 values 为其他元音编写类似的数组和解析逻辑。
第二部分是带变音符号和点号的字符。像“ẹ́”这样的字母在技术上通常是两个独立的字符。在“ẹ́”的情况下,它是“é”和 'combining dot below' character, however in the case of the visually identical "ẹ́", it's "ẹ" and the '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
我正在处理一项 NLP 任务,该任务需要使用称为约鲁巴语的语言的语料库。约鲁巴语是一种在其字母表中有变音符号(口音)和下点的语言。例如,这是一个约鲁巴语字符串:"ọ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"
.
为此我会使用 Unicode normalization。
带有重音符和圆点的字符 precomposed Unicode characters. If you decompose them, you can get the base character plus the combining characters 用于重音符和圆点等等。然后你可以删除你不想要的那些并将字符串重新组合成预组合字符。
您可以在 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']
如您所见,其中一个字符已经部分分解(带有单独 "COMBINING DOT BELOW" 的字符)。现在让我们看看它完全分解:
>>> 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'
由于您想进行特定类型的重音解析,因此您自己编写解析器可能是最简单的方法。本质上,您可以使用 ord()
检查字符串中每个字母的 unicode 值,并对照 unicode 值列表检查是否有不希望有的重音字母。有两个步骤,我的看法是:
首先是处理只有变音符号,没有点号的字符。从我对这种语言的 admittedly cursory research 来看,似乎对于给定的元音,它具有三个可能的变音符号;急性、严重和长音符号。然后,对于给定的元音,您可以创建一个包含每个变音符号变体的 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 values 为其他元音编写类似的数组和解析逻辑。
第二部分是带变音符号和点号的字符。像“ẹ́”这样的字母在技术上通常是两个独立的字符。在“ẹ́”的情况下,它是“é”和 'combining dot below' character, however in the case of the visually identical "ẹ́", it's "ẹ" and the '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