如何将带重音的Unicode字符转换为纯ASCII字符而不带重音?

13

我正在尝试从词典网站下载一些内容,例如http://dictionary.reference.com/browse/apple?s=t

问题在于原始段落中有许多波浪线、反向字母等字符,因此当我读取本地文件时,会得到那些有趣的转义字符,如\x85、\xa7、\x8d等。

我的问题是,是否有任何方法可以将所有这些转义字符转换为它们各自的UTF-8字符,例如如果有一个'à',如何将其转换为标准的'a'?

Python调用代码:

import os
word = 'apple'
os.system(r'wget.lnk --directory-prefix=G:/projects/words/dictionary/urls/ --output-document=G:\projects\words\dictionary\urls/' + word + '-dict.html http://dictionary.reference.com/browse/' + word)

我在Windows 7系统上使用wget-1.11.4-1(请勿谴责我,Linux用户,这是客户的要求),并且wget exe文件是由Python 2.6脚本文件触发的。


2
请展示你的Python代码。 - Raptor
2
将 'à' 转换为 'a' 不像转换为 UTF-8 那样简单。UTF-8 实际上是一种文本编码,旨在编码类似于 'à' 的字符,这些字符不属于 基本 ASCII 字符集 - Phil Frost
5个回答

51

如何将所有转义字符转换成它们对应的字符?例如,如果有一个Unicode字符à,如何将其转换为标准字符a

假设您已经将Unicode加载到名为my_unicode的变量中......将à规范化为a就这么简单......

import unicodedata
output = unicodedata.normalize('NFD', my_unicode).encode('ascii', 'ignore')

显式例子...

>>> myfoo = u'àà'
>>> myfoo
u'\xe0\xe0'
>>> unicodedata.normalize('NFD', myfoo).encode('ascii', 'ignore')
'aa'
>>>

工作原理
unicodedata.normalize('NFD', "插入Unicode文本")执行Unicode文本的规范分解(NFD),然后我们使用str.encode('ascii', 'ignore')将映射为NFD的字符转换为ASCII码(忽略错误)。


太好了Mike。这可能是一个初学者的Python问题,但是,是否可以插入一个字符串,并使unicodedata.norm函数找到任何Unicode转义字符并将其标准化?还是我只能使用正则表达式将Unicode排除并将每个Unicode标准化? - Wolf
当您像我上面所做的那样调用unicodedata.normalize()时,它会找到所有Unicode并将它们规范化为ASCII。您需要做的就是将Unicode文件读入字符串中,在该字符串上调用unicodedata.normalize(),然后将输出保存到新文件名中。 - Mike Pennington
实际上,unicodedata.normalize() 不会将字符串转换为 ASCII;它执行规范分解(基本上是将多部分字符分解成组件);请参见 文档(Python 3.6)str.encode('ascii', 'ignore') 函数将其转换为 ASCII,忽略在非 ASCII 字符中可能出现的错误。请参阅 str.encode错误处理程序 的文档。 - ASL
谢谢您纠正我上面的评论。我已经自作主张地将这些信息编辑到我的答案中了。 - Mike Pennington
我认为对于大多数用例,应该使用NFKD规范化而不是NFD。前者在Unicode术语中是有损的,但这在这里并不重要。‘兼容性’部分意味着更多的Unicode字符被映射到可能正确的输出。将“Dvořák £①”规范化然后转换为ASCII字符,使用NFKDNFD进行比较:在两种情况下,“£”符号都消失了,但在前一种情况下,“①”最终变成了1而不是消失。在许多情况下,这可能是期望的效果。 - Norman Gray
...而且(在重新审查其他答案后的括号注释)几乎肯定不需要NFCNFKC规范化,因为它们会分解然后重新组合,所以随后的ASCII化步骤将删除任何非ASCII字符而不是将它们转换为最接近的ASCII等效字符。 - Norman Gray

5

感谢Mike Pennington提供的解决方案,它很好用。但是当我尝试使用这个解决方案时,我注意到它无法处理一些特殊字符(例如土耳其字母表中的ı字符),因为NFD未定义这些字符。

我发现另一个解决方案,可以使用unidecode库来进行转换。

>>>import unidecode
>>>example = "ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZabcçdefgğhıijklmnoöprsştuüvyz"


#convert it to utf-8
>>>utf8text = unicode(example, "utf-8")

>>> print utf8text
ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZabcçdefgğhıijklmnoöprsştuüvyz

#convert utf-8 to ascii text
asciitext = unidecode.unidecode(utf8text)

>>>print asciitext

ABCCDEFGGHIIJKLMNOOPRSSTUUVYZabccdefgghiijklmnooprsstuuvyz

一般情况下,对于字符串操作非常有帮助。我不明白为什么这个答案的投票数这么少... - Soren V. Raben

2

我需要一个类似的功能,但是只删除有重音的字符,忽略特殊字符,我写了这个小函数:

# ~*~ coding: utf-8 ~*~
import re

def remove_accents(string):
    if type(string) is not unicode:
        string = unicode(string, encoding='utf-8')

    string = re.sub(u"[àáâãäå]", 'a', string)
    string = re.sub(u"[èéêë]", 'e', string)
    string = re.sub(u"[ìíîï]", 'i', string)
    string = re.sub(u"[òóôõö]", 'o', string)
    string = re.sub(u"[ùúûü]", 'u', string)
    string = re.sub(u"[ýÿ]", 'y', string)

    return string

我喜欢这个函数,因为你可以自定义它,以便在需要忽略其他字符时使用。

语法错误:文件source.py中第65行出现非ASCII字符'\xc3',但未声明编码;请参阅http://www.python.org/peps/pep-0263.html了解详情。 - Anoyz
2
需要在文件开头添加:# -- coding: utf-8 -- - Anoyz

0
给定的URL返回UTF-8,因为HTTP响应明确指示:
wget -S http://dictionary.reference.com/browse/apple?s=t
--2013-01-02 08:43:40--  http://dictionary.reference.com/browse/apple?s=t
Resolving dictionary.reference.com (dictionary.reference.com)... 23.14.94.26, 23.14.94.11
Connecting to dictionary.reference.com (dictionary.reference.com)|23.14.94.26|:80... connected.
HTTP request sent, awaiting response... 
  HTTP/1.1 200 OK
  Server: Apache
  Cache-Control: private
  Content-Type: text/html;charset=UTF-8
  Date: Wed, 02 Jan 2013 07:43:40 GMT
  Transfer-Encoding:  chunked
  Connection: keep-alive
  Connection: Transfer-Encoding
  Set-Cookie: sid=UOPlLC7t-zl20-k7; Domain=reference.com; Expires=Wed, 02-Jan-2013 08:13:40 GMT; Path=/
  Set-Cookie: cu.wz=0; Domain=.reference.com; Expires=Thu, 02-Jan-2014 07:43:40 GMT; Path=/
  Set-Cookie: recsrch=apple; Domain=reference.com; Expires=Tue, 02-Apr-2013 07:43:40 GMT; Path=/
  Set-Cookie: dcc=*~*~*~*~*~*~*~*~; Domain=reference.com; Expires=Thu, 02-Jan-2014 07:43:40 GMT; Path=/
  Set-Cookie: iv_dic=1-0; Domain=reference.com; Expires=Thu, 03-Jan-2013 07:43:40 GMT; Path=/
  Set-Cookie: accepting=1; Domain=.reference.com; Expires=Thu, 02-Jan-2014 07:43:40 GMT; Path=/
  Set-Cookie: bid=UOPlLC7t-zlrHXne; Domain=reference.com; Expires=Fri, 02-Jan-2015 07:43:40 GMT; Path=/
Length: unspecified [text/html]

使用vim检查保存的文件还可以发现数据已经正确地进行了utf-8编码...同样,使用Python获取URL也是如此。


是的,那是正确的,但是原帖作者并不是真的想将字符转换为UTF-8,他想要将它们转换为ASCII。 - LarsH

0

对我来说问题有所不同,但这个堆栈页面可以解决它 unicodedata.normalize('NFKC', 'V').encode('ascii', 'ignore') 输出 - b'V'


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