【问题标题】:efficiently replace bad characters有效地替换坏字符
【发布时间】:2011-09-30 09:27:52
【问题描述】:

我经常使用包含以下字符的 utf-8 文本:

\xc2\x99

\xc2\x95

\xc2\x85

这些字符混淆了我使用的其他库,因此需要替换。

什么是执行此操作的有效方法,而不是:

text.replace('\xc2\x99', ' ').replace('\xc2\x85, '...')

【问题讨论】:

  • 您要允许哪些字符?仅 ASCII 码?
  • 我仍然使用 unicode,但是有些字符会导致库中出现需要替换的字符
  • 我相信你会想按照docs.python.org/library/stdtypes.html#str.translate使用text.translate(table)
  • @TryPyPy:让你的评论成为答案,这样我就可以投票了。您可能还想提及 Python 3+ 也有 str.maketrans()
  • str.translate() 仅适用于单字节字符

标签: python string unicode replace


【解决方案1】:

总是有正则表达式;只需在方括号内列出所有有问题的字符,如下所示:

import re
print re.sub(r'[\xc2\x99]'," ","Hello\xc2There\x99")

这会打印:'Hello There',用空格替换不需要的字符。

或者,如果您有不同的替换字符:

# remove annoying characters
chars = {
    '\xc2\x82' : ',',        # High code comma
    '\xc2\x84' : ',,',       # High code double comma
    '\xc2\x85' : '...',      # Tripple dot
    '\xc2\x88' : '^',        # High carat
    '\xc2\x91' : '\x27',     # Forward single quote
    '\xc2\x92' : '\x27',     # Reverse single quote
    '\xc2\x93' : '\x22',     # Forward double quote
    '\xc2\x94' : '\x22',     # Reverse double quote
    '\xc2\x95' : ' ',
    '\xc2\x96' : '-',        # High hyphen
    '\xc2\x97' : '--',       # Double hyphen
    '\xc2\x99' : ' ',
    '\xc2\xa0' : ' ',
    '\xc2\xa6' : '|',        # Split vertical bar
    '\xc2\xab' : '<<',       # Double less than
    '\xc2\xbb' : '>>',       # Double greater than
    '\xc2\xbc' : '1/4',      # one quarter
    '\xc2\xbd' : '1/2',      # one half
    '\xc2\xbe' : '3/4',      # three quarters
    '\xca\xbf' : '\x27',     # c-single quote
    '\xcc\xa8' : '',         # modifier - under curve
    '\xcc\xb1' : ''          # modifier - under line
}
def replace_chars(match):
    char = match.group(0)
    return chars[char]
return re.sub('(' + '|'.join(chars.keys()) + ')', replace_chars, text)

【讨论】:

  • 这是一个很好的方法,但是我们希望为每个设置不同的替换字符
  • 你能举例说明你的意思吗?我很乐意解决一个更具体的案例。
  • Hi Nate - 否决票,因为替换这种方式不是在这种情况下应该做什么,尽管 OP 已经要求这样做。 (好吧,我很痛苦,并且会反对你)- Python 有复杂的机制来来回转换编码字符串,应该使用这些机制。
  • @Steven Rumbalski:你说得对,一旦他改变了问题,我的回答当然就不适用了。
  • regex 仍然可以使用替换函数作为第二个 arg 而不是固定字符串。这是我正在考虑的方法,但想先获得反馈。
【解决方案2】:

如果要从字符串中删除所有非 ASCII 字符,可以使用

text.encode("ascii", "ignore")

【讨论】:

  • 只要确保 text 是一个 unicode 字符串 - 即定义为 text=u"..." - 如果不是,这会引发 UnicodeDecodeError
  • 还要确保您不想只精简为 ASCII! (不用说:p)
【解决方案3】:

这不是“Unicode 字符”——感觉更像是一个 UTF-8 编码的字符串。 (尽管您的前缀应该是 \xC3,而不是大多数字符的 \xC2)。您不应该在 95% 的情况下将它们丢弃,除非您正在与 COBOL 后端通信。你知道,世界不限于 26 个字符。

有一个简明的读物来解释 Unicode 字符串之间的区别(这里在 python 2 中用作 Unicode 对象和在 Python 3 中用作字符串:http://www.joelonsoftware.com/articles/Unicode.html - 为了您的缘故,请务必阅读。即使您永远不会计划在所有应用程序中使用非英语的任何内容,您仍然会偶然发现 € 或 º 等不适合 7 位 ASCII 的符号。那篇文章将对您有所帮助。

也就是说,也许您使用的库确实接受 Unicode python 对象,您可以通过以下操作将 UTF-8 Python 2 字符串转换为 unidoce:

var_unicode = var.decode("utf-8")

如果您真的需要 100% 纯 ASCII,替换所有非 ASCII 字符, 将字符串解码为 un​​icode,将其重新编码为 ASCII,告诉它忽略不适合的字符字符集:

var_ascii = var_unicode.encode("ascii", "replace")

【讨论】:

  • 问题不在于 unicode 与 ascii。我依赖的库和服务支持 utf-8,但会被某些字符绊倒。因此,我将删除它们,因为它们并不重要。
  • “我依赖的库和服务支持 utf-8,但会被某些字符绊倒。”所以它们本身不支持 UTF-8,它们支持 UTF-8 的一个子集。
  • 是的,好的!无论如何,他们声称支持 utf-8。
【解决方案4】:

我认为这里有一个潜在的问题,调查并解决它可能是个好主意,而不是仅仅试图掩盖症状。

\xc2\x95是字符U+0095的UTF-8编码,即C1 control character(MESSAGE WAITING)。您的图书馆无法处理它并不奇怪。但问题是,它是如何进入您的数据的?

嗯,一个很可能的可能性是它以 Windows-1252 编码中的字符 0x95 (BULLET) 开始,被错误地解码为 U+0095 而不是正确的 U+2022,然后编码为 UTF-8 . (日语术语mojibake描述了这种错误。)

如果这是正确的,那么您可以通过将原始字符放回 Windows-1252,然后这次将它们正确解码为 Unicode 来恢复原始字符。 (在这些示例中,我使用的是 Python 3.3;这些操作在 Python 2 中有些不同。)

>>> b'\x95'.decode('windows-1252')
'\u2022'
>>> import unicodedata
>>> unicodedata.name(_)
'BULLET'

如果您想对 0x80–0x99 范围内的所有有效 Windows-1252 字符进行此更正,您可以使用以下方法:

def restore_windows_1252_characters(s):
    """Replace C1 control characters in the Unicode string s by the
    characters at the corresponding code points in Windows-1252,
    where possible.

    """
    import re
    def to_windows_1252(match):
        try:
            return bytes([ord(match.group(0))]).decode('windows-1252')
        except UnicodeDecodeError:
            # No character at the corresponding code point: remove it.
            return ''
    return re.sub(r'[\u0080-\u0099]', to_windows_1252, s)

例如:

>>> restore_windows_1252_characters('\x95\x99\x85')
'•™…'

【讨论】:

  • 有趣。我正在使用的数据是随机的 HTML 页面,所以这似乎很可能。
  • 啊!如果您正在处理随机 HTML 页面,则需要执行 字符编码自动检测。您如何确定页面的编码? (问题很常见,一个页面可能它是用 ISO Latin-1 编码的,但实际上它是在 Windows-1252 中。)
【解决方案5】:

这些字符不在ASCII 库中,这就是您收到错误的原因。 为避免这些错误,您可以在读取文件时执行以下操作。

import codecs   
f = codecs.open('file.txt', 'r',encoding='utf-8')

要了解有关此类错误的更多信息,请转至this link

【讨论】:

    【解决方案6】:
    import unicodedata
    
    # Convert to unicode
    text_to_uncicode = unicode(text, "utf-8")           
    
    # Convert back to ascii
    text_fixed = unicodedata.normalize('NFKD',text_to_unicode).encode('ascii','ignore')         
    

    【讨论】:

    • 对您的答案进行更多解释总是有帮助的。
    猜你喜欢
    • 2011-08-15
    • 1970-01-01
    • 2010-09-22
    • 1970-01-01
    • 2020-03-23
    • 2014-08-11
    • 1970-01-01
    相关资源
    最近更新 更多