在 Python3 里对文本进行重新转义的正确方法

重新转义

在开始之前,先了解一下什么叫做“重新转义”。

本文中的“重新转义”,指的是对一串其内容可以转义的字符串,再一次进行转义,得到该字符串转义过后的新字符串。

举个例子:

# a的内容是一个反斜杠和一个n组合起来的字符串
a = '\\n'

# b与a的内容相同,使用了Python的防止转义语法使文本不转义
b = r'\n'

# 我们希望经过重新转义之后,把“反斜杠+字符”的组合转义成一个转义后的字符
真正的换行符 = 重新转义(a)

在此之前,我曾经使用做过类似的事情:

在Unity uGUI中使用转义字符的方法

现在我将告诉大家,如何在 Python3 中做到同样的事情。

这个问题不简单

如果你用Google搜索这个问题,你可能会得到类似于这样的答案:

print '\\n'.decode('string-escape') # Python2

嗯,对于 Python2 ,这就是正确的做法。(233

如果你在 Python3 中尝试这么做,你会发现 str 类型是没有decode方法的。因为在 Python3 中, str 和 bytes 分离成两个不同的类型了[1]。而且 Python3 使用 Unicode 作为字符串内部编码。

你可能会这么想,既然 str 和 byte 分离了,如果把 str 类型转换成 bytes 类型,不就可以使用 decode 方法了吗?

于是写出这样的代码:

真正的换行符 = bytes('\\n', 'utf-8').decode('unicode-escape')

# 或者这么写
真正的换行符 = '\\n'.encode('utf-8').decode('unicode-escape')

print(真正的换行符)

然后你试了试,好像成功了。

其实没有成功,如果字符串里有中文(应该叫做非ASCII字符)……最后输出的结果里,全都是乱码。

也许你会通过一些奇怪的方式来实现二次转义,例如使用 eval() 函数。请别这么做,这样非常危险。

正确的做法

正确的做法是这样子的:

#! python3
import codecs

# 输出真正的换行符
print(codecs.escape_decode(bytes('\\n', 'utf-8'))[0].decode('utf-8'))

codecs.escape_decode 是一个 bytes 到 bytes 类型的转换器,它会把字符串转义一遍。

举一些例子:

  • b'\\n' → b'\n'
  • b'\\x00' → b'\x00'

这个方法不会考虑 bytes 内容是哪一种字符编码,或者不是字符编码。它只会转义 bytes 里的内容。

我们来总结一下:

import codecs

# Python 2
# 其实 Python2 不能用非 ASCII 字符作为标识符,这里仅供参考
def 重新转义(文本):
    return 文本.decode('string-escape')

# Python 3
def 重新转义(文本):
    return codecs.escape_decode(bytes(文本, 'utf-8'))[0].decode('utf-8')

嗯?你说……[0]是什么情况?

是这样的, escape_decode 返回一个Tuple,第一项为结果,第二项为字节数。


[1]: Python2 里,两者都是 str 类型,或者说 str 类型可以表示两者。

3 条评论

  1. hackdog

    还有这种操作?

  2. 我正处在这个问题之中 看了博主的这个博文 竟然没看懂……

  3. freeman

    太感谢了 这个问题困扰了我很久 爱了

发表评论