Обратная косая черта, экранирующая управляющие символы ascii в середине данных Юникода, безусловно, полезная вещь для достижения. Но это не просто экранирование, а правильное удаление, когда вы хотите вернуть фактические символьные данные.
Должен быть способ сделать это в python stdlib, но его нет. Я подал отчет об ошибке: http://bugs.python.org/issue18679
, но в настоящее время мы используем обходные пути с использованием translate и hackery:
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_escape мог справиться с повторной сборкой всего правильно.
UPDATE
Так что у меня был случай, когда мне нужно было это работать как в python2.7, так и в python3.3. Вот что я сделал (похоронен в модуле _compat.py):
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')