【问题标题】:Python issue with incorrectly formated strings that contains \x包含 \x 的格式不正确的字符串的 Python 问题
【发布时间】:2012-10-11 16:07:27
【问题描述】:

在某些时候,我们的 python 脚本会收到这样的字符串:

In [1]: ab = 'asd\xeffe\ctive'

In [2]: print ab
asd�fe\ctve \ \\ \\\k\\\

数据已损坏,我们需要转义 \x 才能正确解释为 \x,但 \c 在字符串中没有特殊含义,因此必须完好无损。

到目前为止,我找到的最接近的解决方案是:

In [1]: ab = 'asd\xeffe\ctve \\ \\\\ \\\\\\k\\\\\\'

In [2]: print ab.encode('string-escape').replace('\\\\', '\\').replace("\\'", "'")

asd\xeffe\ctve \ \\ \\\k\\\

来自 IPython 的输出,我假设 ab 是一个字符串而不是 unicode 字符串(在后一种情况下,我们将不得不这样做:

def escape_string(s):
    if isinstance(s, str):
        s = s.encode('string-escape').replace('\\\\', '\\').replace("\\'", "'")
    elif isinstance(s, unicode):
        s = s.encode('unicode-escape').replace('\\\\', '\\').replace("\\'", "'")
    return s

【问题讨论】:

  • 一个(脆弱的!)hack 是使用repr,即repr(s)[1:-1]
  • 不要直接打电话给__repr__。拼写为repr(ab)
  • 在字符串数据的源头解决这个问题更有意义。您能否详细说明为什么您首先以ab = 'asd\xeffe\ctive' 的形式接收数据(而不是经过适当清理的ab = 'asd\\xeffe\\ctive')?
  • 如果我们知道损坏的数据是如何进入我们的系统的,我就不会问这个问题了,对吗? :) 我完全同意我们需要修复一个来源,但到目前为止来源是神秘的。我们无法重现用户正在做的任何事情。
  • @Drachenfels:您知道字符串转义将换行符转换为“\\n”(两个字符)以及所有其他有效的转义符吗?

标签: python string unicode


【解决方案1】:

\xhh 是一个转义字符,\x 被视为这个转义的开始。

【讨论】:

    【解决方案2】:

    '\\''\x5c' 相同。将反斜杠字符写为 Python 字符串文字 只是两种不同的方式。

    这些文字字符串:r'\c''\\c''\x5cc''\x5c\x63'相同str 内存中的对象。

    '\xef' 是一个单字节(239 为整数),但r'\xef'(与'\\xef' 相同)是一个 4 字节字符串:'\x5c\x78\x65\x66'

    如果s[0] 返回'\xef',那么它就是s 对象实际包含的内容。如果是错误的,请修复数据的来源。


    注意:string-escape 也可以转义 \n 等:

    >>> print u'''\xef\c\\\N{SNOWMAN}"'\
    ... ☃\u2603\"\'\n\xa0'''.encode('unicode-escape')
    \xef\\c\\\u2603"'\u2603\u2603"'\n\xa0
    >>> print b'''\xef\c\\\N{SNOWMAN}"'\
    ... ☃\u2603\"\'\n\xa0'''.encode('string-escape')
    \xef\\c\\\\N{SNOWMAN}"\'\xe2\x98\x83\\u2603"\'\n\xa0
    

    backslashreplace 仅用于导致UnicodeEncodeError 的字符:

    >>> print u'''\xef\c\\\N{SNOWMAN}"'\
    ... ☃\u2603\"\'\n\xa0'''
    ï\c\☃"'☃☃"'
    
    >>> print b'''\xef\c\\\N{SNOWMAN}"'\
    ... ☃\u2603\"\'\n\xa0'''
    �\c\\N{SNOWMAN}"'☃\u2603"'
    �
    >>> print u'''\xef\c\\\N{SNOWMAN}"'\
    ... ☃\u2603\"\'\n\xa0'''.encode('ascii', 'backslashreplace')
    \xef\c\\u2603"'\u2603\u2603"'
    \xa0
    >>> print b'''\xef\c\\\N{SNOWMAN}"'\
    ... ☃\u2603\"\'\n\xa0'''.decode('latin1').encode('ascii', 'backslashreplace')
    \xef\c\\N{SNOWMAN}"'\xe2\x98\x83\u2603"'
    \xa0
    

    【讨论】:

      【解决方案3】:

      反斜杠引入了“转义序列”。 \x 专门允许您指定一个字节,该字节以 x 后的两个十六进制数字形式给出。 ef 是两个十六进制数字,因此不会出错。将反斜杠加倍以将其转义,或使用原始字符串 r"\xeffective"

      编辑:虽然 Python 控制台可能会向您显示 '\\',但这 正是您所期望的。你只是说你期待别的东西,因为你混淆了字符串及其表示。它是一个包含单个反斜杠的字符串。如果你用print 输出它,你会看到一个反斜杠。

      但字符串文字 '\' 格式不正确(未关闭,因为 \' 是撇号,而不是反斜杠和字符串结尾文字),所以 repr 会在交互时格式化结果壳,不生产它。相反,它会生成一个字符串文字,您可以将其粘贴到 Python 源代码中并获取相同的字符串对象。例如,len('\\') == 1

      【讨论】:

      • 我可能会误解,但我的印象是 OP 的字符串确实是 x = '\xeffective',问题是将其转回 y = '\\xeffective'
      • @DSM 呵呵,我没想到这种解释。可能,但问题非常含糊。在任何一种情况下,OP 似乎都对字符串的表示及其值感到非常困惑。
      【解决方案4】:

      \x 转义序列表示字符串中的 Unicode 字符,ef 被解释为十六进制代码。您可以通过添加额外的 \ 来清理字符串,或者将其设为原始字符串 (r'\xeffective')。

      >>> r'\xeffective'[0]
      '\\'
      

      编辑:您可以使用以下 hack 转换现有字符串:

      >>> a = '\xeffective'
      >>> b = repr(a).strip("'")
      >>> b
      '\\xeffective'
      

      【讨论】:

      • 好的,但是如何将变量转换为“原始”变量。 r'\xeffective' 有效,但如果 ab = '\xeffective' 我该如何实现?
      • @Drachenfels: r'' ("'raw' string") 仅适用于字符串 literals,例如,在您的源代码中。记忆中没有这样的东西。见my answer
      • '\x' not 是否表示 Unicode 字符。 '\xef' 是单个字节(长度为 1 的字节串)。 u'\xef'ï Unicode 字符 (u'\u00ef') 例如,在 utf-8 编码中它是 2 字节:b'\xc3\xaf'
      猜你喜欢
      • 1970-01-01
      • 2012-10-24
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      • 2015-10-05
      • 2021-06-17
      • 2016-08-19
      相关资源
      最近更新 更多