如何在Python中从字符串中删除\xa0?

360
我目前正在使用BeautifulSoup解析HTML文件并调用get_text(), 但好像留下了很多代表空格的Unicode字符\xa0。是否有一种有效的方法可以在Python 2.7中删除所有这些字符并将它们转换为空格?我想更一般化的问题是,是否有一种方法可以去除Unicode格式?
我尝试使用line = line.replace(u'\xa0',' '),如另一个线程所建议的那样,但是这会将\xa0替换为u,因此现在到处都是“u”字母。(:))
编辑:使用str.replace(u'\xa0', ' ').encode('utf-8')似乎解决了问题,但仅使用.encode('utf-8')而不使用replace()似乎会导致输出更奇怪的字符,例如\xc2。能否有人解释这个问题?

已经尝试过了,'ascii'编解码器无法解码位置0的字节0xa0:序数超出范围(128)。 - zhuyxn
19
采用Unicode编码。使用u''代替''。 :-) - jpaugh
2
尝试使用 str.replace(u'\xa0', ' '),但得到了“u”而不是 \xa0 的结果 :/ - zhuyxn
如果字符串是Unicode的,你必须使用u' '替换,而不是' '。原始字符串是Unicode的吗? - pepr
16个回答

414

\xa0实际上是拉丁1(ISO 8859-1)中的不间断空格,也是chr(160)。你应该用空格替换它。

string = string.replace(u'\xa0', u' ')

当使用.encode('utf-8')时,它将unicode编码为utf-8,这意味着每个unicode可以由1到4个字节表示。对于此情况,\xa0由2个字节\xc2\xa0表示。

请查阅http://docs.python.org/howto/unicode.html

请注意:此答案来自2012年,Python已经更新,现在您应该能够使用unicodedata.normalize


18
我对Unicode和字符编码的了解不是很深,但似乎unicodedata.normalize比str.replace更合适。 - dbr
你的字符串处理建议是可行的,但请注意所有对该字符串的引用也需要被替换。例如,如果你有一个打开文件的程序,而其中一个文件名中包含了一个非断行空格,那么你不仅需要进行字符串替换,还需要将该文件重命名。 - user67416
4
[U+00a0]是一个不间断空格的Unicode字符,它可以在latin1编码中被编码为b'\xa0'字节,在UTF-8编码中可以表示为两个字节b'\xc2\xa0'。在HTML中,它可以表示为  - jfs
4
当我尝试这样做时,出现了“UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 397: ordinal not in range(128)”的错误。 - jds
我在一个字符串列表上尝试了这段代码,它没有产生任何作用,而\xa0字符仍然存在。如果我将文本文件重新编码为UTF-8,则该字符将显示为带有胡萝卜的大写A,并且当我将其编码为Unicode时,Python解释器会崩溃。 - Mushroom Man
@dbr unicodedata 不会用 NFC 替换 \xa0(这样可以正确保留带有重音符号的字母,例如 é)。例如:unicodedata.normalize("NFC", "LEFT\xa0RIGHT") == "LEFT\xa0RIGHT" - Jean Monet

328

Python的unicodedata库中有许多有用的功能。其中之一是.normalize()函数。

尝试:

new_str = unicodedata.normalize("NFKD", unicode_str)

如果您使用NFKD无法获得所需的结果,请尝试使用上面链接中列出的任何其他方法进行替换。


4
可能需要使用normalize('NFKD', '1º\xa0dia')来得到'1º dia',但实际返回的是'1o dia'。 - Faccion
5
这里是关于 unicodedata.normalize 的文档,详见链接:https://docs.python.org/zh-cn/3/library/unicodedata.html#unicodedata.normalize - TT--
3
好的,我会尽力进行翻译。以下是您需要翻译的内容:如果文本是“KOREAN”,不要尝试这样做。文字将无法正常显示。 - Cho
3
这个解决方案将俄语字母 й 转换为两个外观相同的 Unicode 字符序列。问题在于,以前相等的字符串现在不匹配了。解决方法是使用 "NFKC" 而不是 "NFKD" - Markus
3
太棒了!这将把单个字母字符串 转换成它实际上的四个字母字符串 ریال。这样在需要替换时就更容易了。您只需对其进行规范化,然后进行替换,而不必关心它是哪一个。normalize("NFKD", "﷼").replace("ریال", '') - Amir Shabani
显示剩余3条评论

41
在尝试了几种方法之后,总结起来,这是我做的方式。以下是两种避免/删除从解析的HTML字符串中的\xa0字符的方法。
假设我们有以下原始HTML:
raw_html = '<p>Dear Parent, </p><p><span style="font-size: 1rem;">This is a test message, </span><span style="font-size: 1rem;">kindly ignore it. </span></p><p><span style="font-size: 1rem;">Thanks</span></p>'

所以让我们试着清理这个HTML字符串:
from bs4 import BeautifulSoup
raw_html = '<p>Dear Parent, </p><p><span style="font-size: 1rem;">This is a test message, </span><span style="font-size: 1rem;">kindly ignore it. </span></p><p><span style="font-size: 1rem;">Thanks</span></p>'
text_string = BeautifulSoup(raw_html, "lxml").text
print text_string
#u'Dear Parent,\xa0This is a test message,\xa0kindly ignore it.\xa0Thanks'

上述代码在字符串中产生了这些字符\xa0。为了正确地删除它们,我们可以使用两种方法。
方法一(推荐): 第一种方法是使用BeautifulSoup的get_text方法,并将strip参数设置为True。 所以我们的代码变成:
clean_text = BeautifulSoup(raw_html, "lxml").get_text(strip=True)
print clean_text
# Dear Parent,This is a test message,kindly ignore it.Thanks

方法 #2: 另一个选项是使用 Python 的库 unicodedata,具体来说是 unicodedata.normalize

import unicodedata
text_string = BeautifulSoup(raw_html, "lxml").text
clean_text = unicodedata.normalize("NFKD",text_string)
print clean_text
# u'Dear Parent,This is a test message,kindly ignore it.Thanks'

我还在这个博客上详细介绍了这些方法,你可以参考。


4
get_text(strip=True) 真的很有用。谢谢老兄。 - ChewChew
这段代码与原始HTML清理后返回Unicode有关,非常具体。它可以完美地工作,但无法删除换行符或制表符。 - Y4RD13

30

尝试在代码行末尾使用 .strip() 方法。我用 line.strip() 得到了很好的效果。


这适用于字符串的开头或结尾。对于其他情况,请使用“replace”。 - 8bitjunkie

20

试试这个:

string.replace('\\xa0', ' ')

6
@RyanMartin说:这个替换了四个字节len(b'\\xa0') == 4,但是len(b'\xa0') == 1。如果可能的话,你应该修复生成这些转义字符的上游代码。 - jfs
4
这个解决方案对我有效:string.replace('\xa0', ' ') - Jenya Pu

17

Python将其视为空格字符,因此您可以使用不带参数的split进行拆分,并通过普通空格进行连接:

line = ' '.join(line.split())

15
我在使用Python从sqlite3数据库中提取数据时遇到了同样的问题。上面的答案对我没有用(不知道为什么),但是这个方法可以:line = line.decode('ascii', 'ignore') 然而,我的目标是删除\xa0,而不是将它们替换为空格。

我从Ned Batchelder的超级有用的Unicode教程中得到了这个方法。


15
你现在正在删除非ASCII字符,这可能掩盖了你实际的问题。使用'ignore'就像强行换挡一样,即使你不明白离合器的工作原理。 - Martijn Pieters
@MartijnPieters 所提供的Unicode教程很好,但您完全正确 - str.encode(...,'ignore')是Unicode处理中的等效于try:... except:...。虽然它可能隐藏错误消息,但很少解决问题。 - dbr
2
对于一些处理电子邮件或URL的目的,似乎使用.decode('ascii', 'ignore')是完美的选择。 - andilabs
2
samwize的回答对你不起作用,因为它适用于Unicode字符串。你的回答中的line.decode()表明你的输入是一个bytestring(你不应该在Unicode字符串上调用.decode()(为了强制执行,此方法在Python 3中已被删除)。我不明白如何可能看到你在答案中链接的教程并错过字节和Unicode之间的区别(不要混淆它们)。 - jfs

13

请尝试此代码

import re
re.sub(r'[^\x00-\x7F]+','','paste your string here').decode('utf-8','ignore').strip()

这适用于字符串的开头或结尾。对于其他情况,请使用“replace”。 - 8bitjunkie

9

在搜索无法打印字符的问题时,我来到了这里。我使用MySQL UTF-8 general_ci 处理波兰语言。对于有问题的字符串,我需要按照以下步骤进行处理:

text=text.replace('\xc2\xa0', ' ')

这只是一个快速的解决方法,你可能应该尝试一些正确的编码设置。


2
如果 text 是一个使用 utf-8 编码的字节串,那么这个方法就可以工作。如果你正在处理文本,请先将其解码为 Unicode(.decode('utf-8')),并且只在最后一步将其编码为字节串(如果 API 不直接支持 Unicode,例如 socket)。所有中间操作都应该在 Unicode 上执行。 - jfs

9
在Python中, \xa0 是一个字符转义序列,表示不间断空格。
不间断空格是一个空格字符,可以防止两个由它分隔的单词之间出现换行符和自动换行。
您可以通过对包含它们的字符串运行replace来去除它们:
my_string.replace('\xa0', '') # no more xa0

6
只有当字符串的开头或结尾包含它时,才会将其移除。 - Bill

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