我在Python中有一个Unicode字符串,我想删除所有重音符号(变音符号)。
我在网上找到了一种在Java中实现这一目标的优雅方式:
我是否需要安装pyICU等库?或者只使用python标准库?那python 3呢?
重要提示:我希望避免代码使用重音字符到非重音字符的显式映射。
答案 0 :(得分:348)
Unidecode是对此的正确答案。它将任何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'
答案 1 :(得分:249)
这个怎么样:
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'
>>>
character category“Mn”代表Nonspacing_Mark
,类似于MiniQuark答案中的unicodedata.combining(我没想到unicodedata.combining,但它可能是更好的解决方案,因为它更明确了。)
请记住,这些操作可能会显着改变文本的含义。口音,变音等不是“装饰”。
答案 2 :(得分:129)
我刚在网上找到了这个答案:
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)
可以与前面的字符组合, c
将返回true,主要是因为它是变音符号。
编辑2 :remove_accents
需要 unicode 字符串,而不是字节字符串。如果你有一个字节字符串,那么你必须将它解码为一个unicode字符串,如下所示:
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)
答案 3 :(得分:26)
实际上我在项目兼容的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'
答案 4 :(得分:16)
这不仅可以处理重音,还可以处理“笔画”(如ø等):
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',因此仍然存在特殊字母,这些字母不会由此处理,例如翻页和倒置字母。这取决于你想要做什么。我有时需要强调剥离来实现字典排序。
答案 5 :(得分:11)
回应@ MiniQuark的回答:
我试图读取一个半法语(包含重音符号)的csv文件以及一些最终会变成整数和浮点数的字符串。
作为测试,我创建了一个test.txt
文件,如下所示:
蒙特利尔,über,12.89,Mère,Françoise,noël,889
我必须包含行2
和3
以使其工作(我在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)
答案 6 :(得分:10)
Gensim - topic modelling for humans:
deaccent("Šéf chomutovských komunistů dostal poštou bílý prášek")
'Sef chomutovskych komunistu dostal postou bily prasek'
另一个解决方案是unidecode。
不建议使用 unicodedata 的建议解决方案通常仅删除某些字符中的重音(例如,它将'ł'
变为''
,而不是'l'
)。
答案 7 :(得分:6)
import unicodedata
from random import choice
import perfplot
import regex
import text_unidecode
def remove_accent_chars_regex(x: str):
return regex.sub(r'\p{Mn}', '', unicodedata.normalize('NFKD', x))
def remove_accent_chars_join(x: str):
# answer by MiniQuark
# https://stackoverflow.com/a/517974/7966259
return u"".join([c for c in unicodedata.normalize('NFKD', x) if not unicodedata.combining(c)])
perfplot.show(
setup=lambda n: ''.join([choice('Málaga François Phút Hơn 中文') for i in range(n)]),
kernels=[
remove_accent_chars_regex,
remove_accent_chars_join,
text_unidecode.unidecode,
],
labels=['regex', 'join', 'unidecode'],
n_range=[2 ** k for k in range(22)],
equality_check=None, relative_to=0, xlabel='str len'
)
答案 8 :(得分:1)
有些语言将变音符号作为语言字母和重音变音符号组合以指定重音。
我认为明确指定要剥离的diactrics是更安全的:
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))
答案 9 :(得分:1)
如果您希望获得类似于 Elasticsearch 的 asciifolding
过滤器的功能,您可能需要考虑 fold-to-ascii,它[本身]...
Apache Lucene ASCII 折叠过滤器的 Python 端口,可将不在前 127 个 ASCII 字符(“基本拉丁语”Unicode 块)中的字母、数字和符号 Unicode 字符转换为 ASCII 等效字符(如果存在)。< /p>
以下是上述页面的示例:
from fold_to_ascii import fold
s = u'Astroturf® paté'
fold(s)
> u'Astroturf pate'
fold(s, u'?')
> u'Astroturf? pate'
EDIT:fold_to_ascii
模块对于标准化拉丁字母似乎很有效;然而,不可映射的字符被删除,这意味着该模块将减少中文文本,例如,为空字符串。如果您想保留中文、日语和其他 Unicode 字母,请考虑使用上面@mo-han 的 remove_accent_chars_regex
实现。