【问题标题】:How to detect non-ASCII character in Python?如何在 Python 中检测非 ASCII 字符?
【发布时间】:2016-05-02 08:06:27
【问题描述】:

我正在使用 Python 2.7 解析多个 XML 文件,其中有一些字符串,例如:string ="[2,3,13,37–41,43,44,46]"。我将它们拆分以获得所有元素的列表,然后我必须检测带有“-”的元素,例如“37-41”,但事实证明这不是常规破折号,而是非 ASCII 字符:

elements = [u'2', u'3', u'13', u'37\u201341', u'43', u'44', u'46']

所以我需要类似的东西

for e in elements:
  if "–" in e:
      # do something about it

如果在此 if 表达式中使用该非 ASCII 字符,则会收到错误消息:"SyntaxError: Non-ASCII character '\xe2' in file..."

我尝试用这个 re 方法替换 if 表达式:

re.search('\xe2', e)

但情况并非如此。所以我正在寻找一种方法,要么将该非 ASCII 字符转换为常规 ASCII“-”,要么直接在搜索表达式中使用 ASCII 数字。

【问题讨论】:

  • 只包含非ascii破折号和数字的元素?
  • @EbraHim 是的。我想检测像 37-41 这样的元素,所以我可以将它们扩展为 37 38 39 40 41。我可以轻松完成第二部分,但我对非 ascii 字符有疑问。
  • Python 2 还是 Python 3?仅 ASCII 字符 (0-127),还是包含 ISO Latin 1 (0-255)?
  • 我正在使用具有 128 个 ASCII 字符的 python 2.7。

标签: python string python-2.7 ascii


【解决方案1】:

您可以检查字符值是否在 0 - 127 之间。

for c in someString:
    if 0 <= ord(c) <= 127:
        # this is a ascii character.
    else:
        # this is a non-ascii character. Do something.

【讨论】:

    【解决方案2】:

    这可能无法回答您的全部问题。太简单了,不够灵活。每当我遇到此错误时,我都会这样做。

    我通常会打开一个交互式 python shell,然后输入:

    print [ln for ln in open("filename.py", "rb").readlines() if "\xe2" in ln]

    这会给你带有 \ex2 的行。然后尝试在您的编辑器中找到它。然后尝试删除该字符。

    【讨论】:

      【解决方案3】:
      # -*- coding: utf-8 -*-
      
      import re
      
      elements = [u'2', u'3', u'13', u'37\u201341', u'43', u'44', u'46']
      
      for e in elements:
          if (re.sub('[ -~]', '', e)) != "":
              #do something here
              print "-"
      

      re.sub('[ -~]', '', e) 会剔除e 中所有有效的 ASCII 字符(具体来说,将所有有效的 ASCII 字符替换为“”),只保留 e 的非 ASCII 字符。

      希望有帮助

      【讨论】:

      • 它工作得很好。只需将最后一次打印更改为print e,它就会准确地打印出我正在寻找的元素。如果您能给我一个文档链接,我将不胜感激,因为语法有点奇怪。
      • 我认为这段代码实际上相当晦涩 - 真的有人能立即看到 if (re.sub('[ -~]', '', e)) != "" 所做的事情吗?
      【解决方案4】:

      试试这个:

      >>> import re
      >>> non_decimal = re.compile(r'[^\d.]+')
      >>>
      >>> string ="[2,3,13,37–41,43,44,46]"
      >>> new_str = string.replace("[","")
      >>> new_str = new_str.replace("]","")
      >>> lst = new_str.split(",")
      >>> for element in lst:
          if element.isdigit():
              print element
          else:
              toexpand = non_decimal.sub('f', str(element))
              toexpand = toexpand.split("f")
              for i in range(int(toexpand[0]),int(toexpand[1])+1,1):
                  print i
      
      
      2
      3
      13
      37
      38
      39
      40
      41
      43
      44
      46
      >>> 
      

      【讨论】:

      • 我想检测包含非 ascii 破折号的元素,例如 37-41。不要忽视它。
      • 我仍然得到 UnicodeDecodeError: 'ascii' codec can't decode byte 0x96 in position 0: ordinal not in range(128) 。我正在使用 PyCharm IDE,这可能会导致问题吗?
      • 糟糕!更新了,但是晚了:)
      【解决方案5】:

      你必须在你的 Python 程序中声明你的编码,例如:

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

      通常 Python 会告诉你这个问题:

      SyntaxError: 第 3 行文件 ./fail.py 中的非 ASCII 字符“\xe2”,但未声明编码;详情见http://www.python.org/peps/pep-0263.html

      添加encoying后,您的代码应该可以正常工作了。

      【讨论】:

      • 它对我不起作用,我正在使用 PyCharm IDE,但我仍然得到 UnicodeDecodeError: UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128 )
      • 这对 Python 2 来说是有意义的,但即便如此也不能直接解决问题中的问题。在 Python 3 中,默认编码无论如何都是 UTF-8;如果您想使用 UTF-8 以外的其他内容(您真的不想这样做,除非您确切地知道自己在做什么,否则您只需要使用编码注释)可能不会读这个)。
      【解决方案6】:

      您可以使用现有的库,例如 chardet(纯 python)或 cchardet(更快的 C 替代方案)。使用例如安装模块pip3 install chardetpip3 install cchardet

      它们都有相同的 API:

      import chardet
      
      with open("/etc/hosts", "rb") as fi:
          print(chardet.detect(fi.read()))
      
      # OUTPUT: 
      # {'encoding': 'ascii', 'confidence': 1.0, 'language': ''}
      

      如果元组中的第一个元素不是 ascii,那么文件中包含非 ascii 字符。

      这两个模块都公开了命令行工具,您可以使用这些工具来检测哪些 XML 文件是非 ASCII:

      find . -iname "*.xml" -exec cchardetect {} +
      

      通常,您只需要在使用非 utf-8/unicode 的未知来源的神秘遗留数据时进行检测。

      如果您有将所有内容转换为 ASCII 的硬性要求,那么您可以执行以下操作:

      import unicodedata
      
      unicodedata.normalize('NFKD', 'Verhältnismäßigkeit — 1').encode('ascii', 'ignore')
      # OUTPUT
      # b'Verhaltnismaigkeit  1'
      

      【讨论】:

        猜你喜欢
        • 2014-01-25
        • 1970-01-01
        • 1970-01-01
        • 2016-04-09
        • 1970-01-01
        • 2015-07-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-14
        相关资源
        最近更新 更多