Проблема Python с неправильно сформированными строками, содержащими x


В какой-то момент наш скрипт python получает такую строку:

In [1]: ab = 'asdxeffective'

In [2]: print ab
asd�fectve  \ \k\

Данные повреждены нам нужно escape x правильно интерпретировать как x, но c не имеет особого значения в строке, поэтому должен быть неповрежденным.

Пока что самое близкое решение, которое я нашел, это сделать что-то вроде:

In [1]: ab = 'asdxeffectve \ \\ \\\k\\\'

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

asdxeffectve  \ \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
4 2

4 ответа:

'\\' это то же самое, что '\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

\xhh является символом побега и \x рассматривается как начало этого побега.

Обратные косые черты вводят "escape-последовательности". \x специально позволяет указать байт, который задается в виде двух шестнадцатеричных цифр после x. ef - это две шестнадцатеричные цифры, следовательно, вы не получите ошибки. Удвоьте обратную косую черту, чтобы избежать ее, или используйте необработанную строку r"\xeffective".

Edit: хотя консоль Python может показать вам '\\', это является именно тем, что вы ожидаете. Вы просто говорите, что ожидаете чего-то другого, потому что путаете строку и ее представление. Это струна. содержит одну обратную косую черту. Если бы вы вывели его с помощью print, Вы бы увидели одну обратную косую черту.

Но строковый литерал '\' плохо сформирован (не закрыт, потому что \' является Апострофом, а не обратной косой чертой и концом строкового литерала), поэтому repr, который форматирует результаты в интерактивной оболочке, не производит его. Вместо этого он создает строковый литерал, который можно вставить в исходный код Python и получить тот же строковый объект. Например, len('\\') == 1.

Escape-последовательность \x обозначает символ Юникода в строке, а ef интерпретируется как шестнадцатеричный код. Вы можете очистить строку, добавив дополнительный \, или же сделать ее сырой строкой (r'\xeffective').

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

EDIT: вы можете преобразовать существующую строку, используя следующий хак:

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