unicode_escape
总的来说不起作用
事实证明,string_escape
or unicode_escape
解决方案通常无法正常工作-尤其是在存在实际Unicode的情况下,它不能正常工作。
如果您可以确定每个非ASCII字符都会被转义(并且请记住,前128个字符以外的任何字符都是非ASCII),unicode_escape
将为您做正确的事。但是,如果您的字符串中已经有任何文字上的非ASCII字符,则会出错。
unicode_escape
从根本上来说是设计用来将字节转换为Unicode文本。但是在许多地方(例如Python源代码),源数据已经是Unicode文本。
唯一可以正常工作的方法是首先将文本编码为字节。UTF-8是所有文本的明智编码,因此应该可以使用,对吧?
以下示例是Python 3中的示例,因此字符串文字更清晰,但在Python 2和3上,存在相同的问题,但表现形式略有不同。
>>> s = 'naïve \\t test'
>>> print(s.encode('utf-8').decode('unicode_escape'))
naïve test
好吧,那是错误的。
建议使用编解码器将文本解码为文本的新方法是codecs.decode
直接调用。有帮助吗?
>>> import codecs
>>> print(codecs.decode(s, 'unicode_escape'))
naïve test
一点也不。(此外,以上是Python 2上的UnicodeError。)
该unicode_escape
编解码器,尽管它的名字,原来假设所有非ASCII字节拉丁-1(ISO-8859-1)编码。因此,您必须这样做:
>>> print(s.encode('latin-1').decode('unicode_escape'))
naïve test
但这太可怕了。这将您限制为256个Latin-1字符,就好像根本没有发明Unicode一样!
>>> print('Ernő \\t Rubik'.encode('latin-1').decode('unicode_escape'))
UnicodeEncodeError: 'latin-1' codec can't encode character '\u0151'
in position 3: ordinal not in range(256)
添加正则表达式以解决问题
(令人惊讶的是,我们现在没有两个问题。)
我们需要做的只是将unicode_escape
解码器应用于我们确定为ASCII文本的内容。特别是,我们可以确保仅将其应用于有效的Python转义序列,这些序列必须保证为ASCII文本。
计划是,我们将使用正则表达式查找转义序列,并使用函数作为参数以re.sub
将其替换为未转义的值。
import re
import codecs
ESCAPE_SEQUENCE_RE = re.compile(r'''
( \\U........ # 8-digit hex escapes
| \\u.... # 4-digit hex escapes
| \\x.. # 2-digit hex escapes
| \\[0-7]{1,3} # Octal escapes
| \\N\{[^}]+\} # Unicode characters by name
| \\[\\'"abfnrtv] # Single-character escapes
)''', re.UNICODE | re.VERBOSE)
def decode_escapes(s):
def decode_match(match):
return codecs.decode(match.group(0), 'unicode-escape')
return ESCAPE_SEQUENCE_RE.sub(decode_match, s)
然后:
>>> print(decode_escapes('Ernő \\t Rubik'))
Ernő Rubik
'spam'+"eggs"+'''some'''+"""more"""
处理有多精确?