【问题标题】:How to make the python interpreter correctly handle non-ASCII characters in string operations?如何让python解释器正确处理字符串操作中的非ASCII字符?
【发布时间】:2010-11-23 10:36:48
【问题描述】:

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

6 918 417 712

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

s.replace('Â ', '')

这应该可以解决问题。但它当然会抱怨文件 blabla.py 中的非 ASCII 字符 '\xc2' 未编码。

我一直不太明白如何在不同的编码之间切换。

这里是代码,它真的和上面一样,但现在它在上下文中。该文件在记事本中保存为 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...

【问题讨论】:

  • 到目前为止尝试了所有 4 个答案。不去。仍然收到 UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 1: ordinal not in range(128)
  • 你的 unicode 字符串必须前面加上u
  • @SilentGhost:如您所见,无法确定它是 unicode 字符串。我得到一个包含上面显示的内容的字符串,但它包含非 ascii 字符串。这才是真正的问题。我猜它是 unicode,因为它不在前 128 个中。
  • 该错误与传入的字符串无关。是你代码中的一个字符串引发了这个错误!
  • 我敢打赌这就是 Python 3 对字符串和字节序列之间的区别如此严格的原因,只是为了避免这种混淆。

标签: python unicode


【解决方案1】:

扔掉所有不能解释为ASCII的字符:

def remove_non_ascii(s):
    return "".join(c for c in s if ord(c)<128)

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

【讨论】:

  • 我得到:TypeError: ord() 期望一个字符,但找到长度为 2 的字符串
  • @Ivelin 那是因为“字符”没有被解释为正确的 unicode...如果它是文字,请检查您的源字符串是否以 u 为前缀。
【解决方案2】:

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""),但在 Python 3 中,只需使用引号。在 Python 2 中,您可以from __future__ import unicode_literals 获取 Python 3 的行为,但请注意这会影响整个当前模块。

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

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

【讨论】:

  • 你实际上只需要# coding: utf-8-*- 不是用来装饰的,但你不太可能需要它。我想它是用来存放旧贝壳的。
【解决方案3】:
>>> unicode_string = u"hello aåbäcö"
>>> unicode_string.encode("ascii", "ignore")
'hello abc'

【讨论】:

  • 我看到了你得到的选票,但是当我尝试它时它说:不。 UnicodeDecodeError:“ascii”编解码器无法解码位置 1 中的字节 0xc2:序数不在范围内(128)。难道是我的原始字符串不是Unicode?无论如何。它需要
  • 很好,谢谢。我可以建议在结果上使用 .decode() 来获得原始编码吗?
  • 如果遇到 UnicodeDecodeError: 'ascii',请在应用编码功能之前尝试将字符串转换为 ''UTF-8' 格式。
【解决方案4】:

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

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

【讨论】:

  • 出于好奇,我想知道,有什么具体的理由用问号代替吗?
【解决方案5】:

使用正则表达式:

import re

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

【讨论】:

    【解决方案6】:

    答案为时已晚,但原始字符串采用 UTF-8 格式,而 '\xc2\xa0' 是 UTF-8 表示 NO-BREAK SPACE。只需将原始字符串解码为s.decode('utf-8')(当解码错误为 Windows-1252 或 latin-1 时,\xa0 显示为空格:

    示例(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
    

    【讨论】:

      【解决方案7】:
      #!/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:序数不在范围内(128)。难道是我的原始字符串不是Unicode?无论如何。我可能做错了什么。
      • @adergaard,您是否在源文件顶部添加了# -- coding: utf-8 --?
      • 是的,再次查看此页顶部,我已经编辑了问题并放入了代码和标题 cmets。感谢您的帮助。
      • 我认为您必须弄清楚如何从 html 或 xml 文档中获取 unicode 中的字符串。更多信息在这里:diveintopython.org/xml_processing/unicode.html
      【解决方案8】:

      我知道这是一个旧线程,但我不得不提及 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() 作为键的 dict。但是无论如何从一个unicode字符串中得到一个正确的ascii字符串是很简单的,使用上面truppo提到的方法,即: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:字符映射必须返回整数、无或 unicode
      【解决方案9】:
      s.replace(u'Â ', '')              # u before string is important
      

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

      【讨论】:

        【解决方案10】:

        这是一个肮脏的黑客,但可能会奏效。

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

        【讨论】:

        【解决方案11】:

        不管怎样,我的字符集是utf-8,并且我已经包含了经典的“# -*- coding: utf-8 -*-”行。

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

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

        当我循环浏览并看到有问题的字符集时,我意识到了错误。

        所以,它也可能在 ASCII 字符集中,但是是你没想到的字符。

        【讨论】:

          【解决方案12】:

          我的 2 便士和美味的汤,

          string='<span style="width: 0px> dirty text begin ( ĀĒēāæśḍṣ <0xa0> ) dtext end </span></span>'
          string=string.encode().decode('ascii',errors='ignore')
          print(string)
          

          会给

          <span style="width: 0px> dirty text begin (   ) dtext end </span></span>
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-10-15
            • 2013-03-22
            • 1970-01-01
            • 2010-12-11
            • 2016-10-31
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多