如何使python解释器正确处理字符串操作中的非ASCII字符?


104

我有一个看起来像这样的字符串:

6 918 417 712

修剪此字符串的明确方法(据我了解Python)只是说该字符串在名为的变量中s,我们得到:

s.replace('Â ', '')

这应该够了吧。但是,当然,它抱怨'\xc2'文件blabla.py 中的非ASCII字符未编码。

我从不完全了解如何在不同的编码之间进行切换。

这是代码,它的确与上面的代码相同,但是现在是在上下文中。该文件在记事本中另存为UTF-8,并具有以下标头:

#!/usr/bin/python2.4
# -*- coding: utf-8 -*-

代码:

f = urllib.urlopen(url)

soup = BeautifulSoup(f)

s = soup.find('div', {'id':'main_count'})

#making a print 's' here goes well. it shows 6Â 918Â 417Â 712

s.replace('Â ','')

save_main_count(s)

它没有比s.replace... 更进一步


1
到目前为止,已尝试了所有4个答案。不行 仍然收到UnicodeDecodeError:'ascii'编解码器无法解码位置1的字节
0xc2

您的unicode字符串必须u
SilentGhost

@SilentGhost:如您所见,无法确定它是unicode字符串。我得到的字符串具有上面显示的内容,但其中包含非ascii字符串。那是真正的问题。我猜它是unicode,因为它不在前128个中
。– adergaard

该错误与传入字符串无关。这是您的代码中的字符串,引发此错误!
SilentGhost

2
我敢打赌,这就是为什么Python 3如此严格地对待字符串和字节序列之间的区别,只是为了避免这种混淆。
马克·兰索姆

Answers:


84

Python 2 ascii用作源文件的默认编码,这意味着您必须在文件顶部指定其他编码,才能在文字中使用非ASCII Unicode字符。Python 3 utf-8用作源文件的默认编码,因此这没有什么问题。

请参阅:http : //docs.python.org/tutorial/interpreter.html#source-code-encoding

要启用utf-8源编码,将在前两行之一进行:

# -*- coding: utf-8 -*-

上面是在文档中,但这也可以:

# coding: utf-8

其他注意事项:

  • 还必须在文本编辑器中使用正确的编码来保存源文件。

  • 在Python 2中,unicode字面量必须在其u前面,就像在s.replace(u"Â ", u"")But 3中一样,只需使用引号即可。在Python 2中,您from __future__ import unicode_literals可以获得Python 3的行为,但是请注意,这会影响整个当前模块。

  • s.replace(u"Â ", u"")如果s不是unicode字符串,也会失败。

  • string.replace 返回一个新的字符串,并且不会在原地编辑,因此请确保您也使用了返回值


4
您实际上只需要# coding: utf-8-*-不是用于装饰,但您不太可能需要它。我认为那是旧贝壳的地方。
fmalina

157
def removeNonAscii(s): return "".join(filter(lambda x: ord(x)<128, s))

编辑:我的第一个冲动总是使用过滤器,但是生成器表达式的存储效率更高(并且更短)...

def removeNonAscii(s): return "".join(i for i in s if ord(i)<128)

请记住,这保证可以使用UTF-8编码(因为多字节字符中的所有字节的最高位都设置为1)。


1
我得到:TypeError:ord()需要一个字符,但是找到了长度为2的字符串
Ivelin

@Ivelin,这是因为“字符”没有被解释为正确的unicode ...请检查源字符串是否以u字面量为前缀。
fortran

35
>>> unicode_string = u"hello aåbäcö"
>>> unicode_string.encode("ascii", "ignore")
'hello abc'

4
我看到您所获得的票,但是当我尝试时它说:不。UnicodeDecodeError:“ ascii”编解码器无法解码位置1的字节0xc2:序数不在range(128)中。难道我的原始字符串不是unicode吗?好吧,无论如何。它需要
adergaard

2
很好,谢谢。我是否可以建议对结果使用.decode()使其以原始编码形式获得?
AkiRoss 2012年

如果您收到UnicodeDecodeError:'ascii',则尝试在应用编码功能之前将字符串转换为“ UTF-8”格式。
Sateesh

16

以下代码将所有非ASCII字符替换为问号。

"".join([x if ord(x) < 128 else '?' for x in s])

出于好奇,我想知道,是否有任何特定原因将其替换为问号?
Mohsin

6

使用正则表达式:

import re

strip_unicode = re.compile("([^-_a-zA-Z0-9!@#%&=,/'\";:~`\$\^\*\(\)\+\[\]\.\{\}\|\?\<\>\\]+|[^\s]+)")
print strip_unicode.sub('', u'6Â 918Â 417Â 712')

5

答案太迟了,但是原始字符串位于UTF-8中,对于NO-BREAK SPACE,'\ xc2 \ xa0'为UTF-8。只需将原始字符串解码为s.decode('utf-8')(\ xa0在Windows-1252或latin-1错误解码时显示为空格:

示例(Python 3)

s = b'6\xc2\xa0918\xc2\xa0417\xc2\xa0712'
print(s.decode('latin-1')) # incorrectly decoded
u = s.decode('utf8') # correctly decoded
print(u)
print(u.replace('\N{NO-BREAK SPACE}','_'))
print(u.replace('\xa0','-')) # \xa0 is Unicode for NO-BREAK SPACE

输出量

6 918 417 712
6 918 417 712
6_918_417_712
6-918-417-712

3
#!/usr/bin/env python
# -*- coding: utf-8 -*-

s = u"6Â 918Â 417Â 712"
s = s.replace(u"Â", "") 
print s

这将打印出来 6 918 417 712


不。UnicodeDecodeError:“ ascii”编解码器无法解码位置1的字节0xc2:序数不在range(128)中。难道我的原始字符串不是unicode吗?好吧,无论如何。我可能做错了。
09年

@adergaard,您是否在源文件顶部添加#-- 编码:utf- 8-- ?
Nadia Alramli 2009年

是的,再次查看此页面的顶部,我已经编辑了问题代码,并输入了代码和标头注释。谢谢你的协助。
adergaard

我认为您将必须弄清楚如何从Unicode的html或xml文档中获取字符串。此处的更多信息:diveintopython.org/xml_processing/unicode.html
以赛亚书2009年

2

我知道这是一个旧线程,但是我不得不提一下translate方法,这始终是替换128以上所有字符代码(或必要时其他字符)的一种好方法。

用法:str。翻译table [,deletechars]

>>> trans_table = ''.join( [chr(i) for i in range(128)] + [' '] * 128 )

>>> 'Résultat'.translate(trans_table)
'R sultat'
>>> '6Â 918Â 417Â 712'.translate(trans_table)
'6  918  417  712'

Python 2.6开始,您还可以将表设置为None,并使用deletechars删除不需要的字符,如http://docs.python.org/library/stdtypes上标准文档中显示的示例中所示。 html

对于unicode字符串,转换表不是256个字符的字符串,而是以相关字符的ord()作为键的字典。但是无论如何,使用上面truppo提到的方法从unicode字符串中获取适当的ascii字符串就足够简单了,即:unicode_string.encode(“ ascii”,“ ignore”)

总结一下,如果由于某种原因您绝对需要获取ascii字符串(例如,当您使用引发标准异常时raise Exception, ascii_message),可以使用以下函数:

trans_table = ''.join( [chr(i) for i in range(128)] + ['?'] * 128 )
def ascii(s):
    if isinstance(s, unicode):
        return s.encode('ascii', 'replace')
    else:
        return s.translate(trans_table)

翻译的好处是,您实际上可以将重音符号转换为相关的非重音ascii字符,而不是简单地将其删除或用'?'代替。这通常很有用,例如用于索引目的。


我得到:TypeError:字符映射必须返回整数,None或unicode
Ivelin

1
s.replace(u'Â ', '')              # u before string is important

并使您的.py文件成为unicode。


1

这是一个肮脏的骇客,但可能行得通。

s2 = ""
for i in s:
    if ord(i) < 128:
        s2 += i

0

就其价值而言,我的角色是,utf-8而且我包括了经典的“# -*- coding: utf-8 -*- ”系列。

但是,我发现从网页读取此数据时没有通用换行符。

我的文字有两个词,以“ \r\n” 分隔。我只是拆分\n并替换"\n"

当我遍历并看到有问题的字符集后,我意识到了这个错误。

因此,它也可以在ASCII字符集中,但不是您所期望的字符。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.