【问题标题】:Regular expression that finds and replaces non-ascii characters with Python用 Python 查找和替换非 ascii 字符的正则表达式
【发布时间】:2010-05-03 14:54:44
【问题描述】:

我需要将一些非 ASCII 字符更改为“_”。 例如,

Tannh‰user -> Tannh_user
  • 如果我在 Python 中使用正则表达式,我该怎么做?
  • 不使用 RE 有没有更好的方法来做到这一点?

【问题讨论】:

    标签: python regex


    【解决方案1】:
    re.sub(r'[^\x00-\x7F]', '_', theString)
    

    如果字符串是 unicode,或者 ASCII 占用值 0 到 0x7F(latin-1、UTF-8 等)的编码字符串,这将起作用。

    【讨论】:

      【解决方案2】:

      回答问题

      '[\u0080-\uFFFF]'
      

      将匹配任何不在前 128 个字符范围内的 UTF-8 字符

      re.sub('[\u0080-\uFFFF]+', '_', x)
      

      将用下划线替换任何连续的非ASCII字符序列

      【讨论】:

      • 很高兴看到有人回答了这个问题!即使在列表的底部
      【解决方案3】:

      使用神奇的正则表达式[ -~] 可以解决它:

      import re
      re.sub(r"[^ -~]", "_", "Tannh‰user")
      # 'Tannh_user'
      

      解释:

      • ascii 字符是符号 ranging from " " to "~" - 因此 [ -~] 捕获所有 ascii 字符
      • 通过附加^我们可以捕获所有非ascii字符
      • 现在剩下的就是形式了

      【讨论】:

        【解决方案4】:

        针对 Python 3 更新:

        >>> 'Tannh‰user'.encode().decode('ascii', 'replace').replace(u'\ufffd', '_')
        'Tannh___user'
        

        首先我们使用encode() 创建字节串——它默认使用UTF-8 编解码器。如果你有字节串,那么当然跳过这个编码步骤。 然后我们使用 ascii 编解码器将其转换为“普通”字符串。

        这使用了 UTF-8 的属性,即所有非 ascii 字符都被编码为值 >= 0x80 的字节序列。


        原始答案 - 针对 Python 2:

        如何使用内置的str.decode 方法:

        >>> 'Tannh‰user'.decode('ascii', 'replace').replace(u'\ufffd', '_')
        u'Tannh___user'
        

        (您会得到unicode 字符串,因此如果需要,请将其转换为str。)

        您还可以将unicode 转换为str,因此将一个非ASCII 字符替换为一个ASCII 字符。但问题是unicode.encodereplace 将非ASCII 字符转换为'?',所以你不知道问号之前是否已经存在;请参阅 Ignacio Vazquez-Abrams 的解决方案。


        另一种方式,使用 ord() 并比较每个字符的值是否适合 ASCII 范围 (0-127) - 这适用于 unicode 字符串和 utf-8、拉丁文和其他一些编码中的 str

        >>> s = 'Tannh‰user' # or u'Tannh‰user' in Python 2
        >>> 
        >>> ''.join(c if ord(c) < 128 else '_' for c in s)
        'Tannh_user'
        

        【讨论】:

        • 不是百分比 % 而是 ‰ 。不确定它仍然是ascii。是吗?
        • 这是 U+2030 字符,每千位符号(不是 ASCII)。
        【解决方案5】:

        使用 Python 对字符编码的支持:

        # coding: utf8
        import codecs
        
        def underscorereplace_errors(exc):
          return (u'_', exc.end)
        
        codecs.register_error('underscorereplace', underscorereplace_errors)
        
        print u'Tannh‰user'.encode('ascii', 'underscorereplace')
        

        【讨论】:

          【解决方案6】:

          我宁愿只在字符串中的每个字符上调用 ord,1 比 1。如果 ord([char]) &gt;= 128 字符不是 ascii 字符,应该被替换。

          【讨论】:

            【解决方案7】:

            如果您知道要替换哪些字符,则可以应用字符串方法

            mystring.replace('oldchar', 'newchar')
            

            【讨论】:

            • -1:首先应该是ord(item)&gt;127。然后,想想你的代码对这个字符串做了什么:'\xa0'*1000.
            • @ΤZΩΤZΙΟΥ 被否决的部分已被删除。请注意,尽管您是对的,并且它无法管理 '\xa0' 类型表示,但它与我理解的任何单字符可打印符号完美配合是 OP 正在与之抗争的字符串类型。另请注意,另一篇文章提出了相同的方法。
            • 我删除了我的反对票,但我找不到任何其他答案:对于输入字符串中的每个适用字符,替换整个输入字符串我>。在我的'\xa0'*1000 示例中,您的代码执行了整个mystring 替换一千次,其中999 次是不必要的。如果你不同意这一点,那么给定astr='hello'; c=0,在这个循环之后c 的值是多少:for char in astr: c+= 1; astr=''?我说是 5,你可能认为是 1。
            • Brian 的回答提出了相同的方法:检查字符串中每个字符的 ord() 值,如果超过 127 则替换它。我现在明白你的意思了。在您发表第一条评论后,我意识到我的代码无法与 mystring = '\xa0' 一起使用,因为它正在检查 '\',然后是 'x'......所以我认为这是你的意思。现在我明白你提到了我错过的另一件事:for 循环中的字符串在搜索过程中是不变的,因此即使重复的字符已经在循环内的变量中被替换,也会被检查。效率不是很高。谢谢!
            猜你喜欢
            • 1970-01-01
            • 2021-05-18
            • 2015-04-27
            • 1970-01-01
            • 2012-11-21
            • 2013-02-19
            • 1970-01-01
            • 1970-01-01
            • 2013-09-22
            相关资源
            最近更新 更多