Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/solr/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python2中编码转义字符而不破坏Unicode的正确方法是什么?_Python_Unicode_Encoding - Fatal编程技术网

在Python2中编码转义字符而不破坏Unicode的正确方法是什么?

在Python2中编码转义字符而不破坏Unicode的正确方法是什么?,python,unicode,encoding,Python,Unicode,Encoding,我想我对Python的unicode字符串非常着迷。我正在尝试将转义字符编码为Unicode字符串,而不转义实际的Unicode字符。我明白了: In [14]: a = u"Example\n" In [15]: b = u"Пример\n" In [16]: print a Example In [17]: print b Пример In [18]: print a.encode('unicode_escape') Example\n In [19]: print b.e

我想我对Python的unicode字符串非常着迷。我正在尝试将转义字符编码为Unicode字符串,而不转义实际的Unicode字符。我明白了:

In [14]: a = u"Example\n"

In [15]: b = u"Пример\n"

In [16]: print a
Example


In [17]: print b
Пример


In [18]: print a.encode('unicode_escape')
Example\n

In [19]: print b.encode('unicode_escape')
\u041f\u0440\u0438\u043c\u0435\u0440\n
虽然我非常需要(很明显,英语示例可以满足我的需要):

除了转到Python 3,我应该怎么做


PS:正如下面指出的,我实际上是想逃避控制角色。我是否需要的不仅仅是这些,还需要观察。

方法
.encode
返回一个字节字符串(在Python 2中键入
str
),因此它不能返回unicode字符

但由于序列很少,您可以轻松地
。手动更换它们。

有关完整列表,请参阅。

首先,让我们更正术语。您试图做的是用等效的“转义序列”替换“控制字符”

我还没有找到任何内置的方法来实现这一点,也没有人发布过。幸运的是,编写这个函数并不难

control_chars = [unichr(c) for c in range(0x20)] # you may extend this as required

def control_escape(s):
    chars = []
    for c in s:
        if c in control_chars:
            chars.append(c.encode('unicode_escape'))
        else:
            chars.append(c)
    return u''.join(chars)
或可读性稍差的单行程序版本:

def control_escape2(s):
    return u''.join([c.encode('unicode_escape') if c in control_chars else c for c in s])
.encode('unicode_escape')
返回一个字节字符串。您可能希望直接在Unicode字符串中转义控制字符:

输出:

\x0d\x09\x08马克\x0a
\u000dMark\u0009\u0008马克\u000a
注意,0-31之外还有其他Unicode控制字符,因此您可能需要类似以下内容:

# coding: utf8
import re
import unicodedata as ud

def esc(m):
    c = m.group(0)
    if ud.category(c).startswith('C'):
        return u'\\u{:04x}'.format(ord(c))
    return c

s = u'\rMark\t\b马克\n'

# Match ALL characters so the replacement function
# can test the category.  Not very efficient if the string is long.
print re.sub(ur'(?s).',esc,s)
输出:

\x0d\x09\x08马克\x0a
\u000dMark\u0009\u0008马克\u000a
您可能希望更好地控制被视为控制字符的内容。这里有很多。您可以构建与特定类型匹配的正则表达式:

import sys
import re
import unicodedata as ud

# Generate a regular expression that matches any Cc category Unicode character.
Cc_CODES = u'(?s)[' + re.escape(u''.join(unichr(n) for n in range(sys.maxunicode+1) if ud.category(unichr(n)) == 'Cc')) + u']'

反斜杠在Unicode数据中间逃逸ASCII控制字符绝对是一件有用的事情。但这不仅仅是转义,当你想要返回实际的字符数据时,它还可以正确地转义

在python stdlib中应该有一种方法可以做到这一点,但是没有。我提交了一份bug报告:

但同时,这里有一个关于使用翻译和黑客的工作:

tm = dict((k, repr(chr(k))[1:-1]) for k in range(32))
tm[0] = r'\0'
tm[7] = r'\a'
tm[8] = r'\b'
tm[11] = r'\v'
tm[12] = r'\f'
tm[ord('\\')] = '\\\\'

b = u"Пример\n"
c = b.translate(tm)
print(c) ## results in: Пример\n
所有非反斜杠单字母控制字符都将使用\x##序列进行转义,但如果需要对这些字符执行其他操作,则可以使用翻译矩阵进行转义。这种方法不会有损,所以对我来说很有效

但是要把它重新翻译出来也很困难,因为你不能仅仅用translate把字符序列翻译成单个字符

d = c.encode('latin1', 'backslashreplace').decode('unicode_escape')
print(d) ## result in Пример with trailing newline character
实际上,您必须使用latin1对映射到字节的字符进行单独编码,同时对latin1不知道的unicode字符进行反斜杠转义,以便unicode_转义编解码器能够以正确的方式重新组装所有内容

更新

所以我有一个案例,我需要它在python2.7和python3.3中工作。下面是我所做的(嵌入到一个_compat.py模块中):


您要对哪些字符进行编码?只是
\r\n\t
?没有“逃避角色”这样的东西。问题是,你的要求是自相矛盾的。Python 2字符串(Python 3
字节
)不包含unicode字符。它们只包含字节。这些字节可能是存储在特定编码中的unicode代码点,但它们仍然只是字节。如果要存储unicode,请使用
unicode
。如果您想要字节,请使用字节-但是您没有unicode,您只有字节,而没有UTF-*的信息。它可能是一些奇怪的8位代码页。另请参阅其中提供的一些见解和一般方法。@agf本质上是每个“特殊”字符。至少我希望Python知道Unicode代码点是一个字母,不要管它。@rassie您需要定义“特殊”字符。可能您只需要将其编码为utf-8或其他格式,然后使用正则表达式。没有一种标准编码可以满足您的需要。@delnan:据我所知,我使用的是
unicode
(可能我错了)。老实说,我不明白为什么转义函数转义西里尔字母,但不涉及拉丁字母(如果它也编码拉丁字母,我也不会抱怨!)我的用例:我正在玩
ast
,希望输出与原始代码类似的字符串,即,我需要能够输出
“ППППППППМППППППППППППППППППППППМММММ
。如果没有不完整的破解,比如只替换转义序列的子集,这是不可能的。哦,是的,“控制字符”完全忘记了这个术语。所以现在的问题是如何解码你创建的字符串?当我尝试这样做时,我有正确的字节字符串,但我不能后退。@underrun,如果这是一个问题,你真的有你应该张贴它作为一个新的问题。我没有一个快速的答案。
if isinstance(b"", str):                                                        
    byte_types = (str, bytes, bytearray)                                        
    text_types = (unicode, )                                                    
    def uton(x): return x.encode('utf-8', 'surrogateescape')                    
    def ntob(x): return x                                                       
    def ntou(x): return x.decode('utf-8', 'surrogateescape')                    
    def bton(x): return x
else:                                                                           
    byte_types = (bytes, bytearray)                                             
    text_types = (str, )                                                        
    def uton(x): return x                                                       
    def ntob(x): return x.encode('utf-8', 'surrogateescape')                    
    def ntou(x): return x                                                       
    def bton(x): return x.decode('utf-8', 'surrogateescape')    

escape_tm = dict((k, ntou(repr(chr(k))[1:-1])) for k in range(32))              
escape_tm[0] = u'\0'                                                            
escape_tm[7] = u'\a'                                                            
escape_tm[8] = u'\b'                                                            
escape_tm[11] = u'\v'                                                           
escape_tm[12] = u'\f'                                                           
escape_tm[ord('\\')] = u'\\\\'

def escape_control(s):                                                          
    if isinstance(s, text_types):                                               
        return s.translate(escape_tm)
    else:
        return s.decode('utf-8', 'surrogateescape').translate(escape_tm).encode('utf-8', 'surrogateescape')

def unescape_control(s):                                                        
    if isinstance(s, text_types):                                               
        return s.encode('latin1', 'backslashreplace').decode('unicode_escape')
    else:                                                                       
        return s.decode('utf-8', 'surrogateescape').encode('latin1', 'backslashreplace').decode('unicode_escape').encode('utf-8', 'surrogateescape')