Как избежать экранирования строки с обратной косой чертой?

101

Предположим, у меня есть строка, которая является версией другой строки с экранированной обратной косой чертой. Есть ли простой способ в Python отменить экранирование строки? Я мог бы, например, сделать:

>>> escaped_str = '"Hello,\\nworld!"'
>>> raw_str = eval(escaped_str)
>>> print raw_str
Hello,
world!
>>> 

Однако это предполагает передачу (возможно, ненадежной) строки в eval (), что представляет угрозу безопасности. Есть ли в стандартной библиотеке функция, которая принимает строку и производит строку без последствий для безопасности?

Ник
источник

Ответы:

138
>>> print '"Hello,\\nworld!"'.decode('string_escape')
"Hello,
world!"
ChristopheD
источник
9
Есть ли что-то совместимое с python 3?
thejinx0r
3
@ thejinx0r: посмотрите сюда: stackoverflow.com/questions/14820429/…
ChristopheD
30
В основном для Python3, который вам нуженprint(b"Hello,\nworld!".decode('unicode_escape'))
ChristopheD
3
Для python 3 используйтеvalue.encode('utf-8').decode('unicode_escape')
Casey Kuball
8
ВНИМАНИЕ: value.encode('utf-8').decode('unicode_escape') повреждает не-ASCII символы в строке . Это недопустимое решение, если только вводимые данные не содержат только символы ASCII.
Alex Peters
35

Вы можете использовать то, ast.literal_evalчто безопасно:

Безопасно оцените узел выражения или строку, содержащую выражение Python. Предоставленная строка или узел могут состоять только из следующих литеральных структур Python: строки, числа, кортежи, списки, словари, логические значения и None. (КОНЕЦ)

Как это:

>>> import ast
>>> escaped_str = '"Hello,\\nworld!"'
>>> print ast.literal_eval(escaped_str)
Hello,
world!
джатанизм
источник
3
Наличие в строке экранированной точки с запятой нарушает этот код. Выдает синтаксическую ошибку «неожиданный символ после символа продолжения строки»
darksky 01
3
@darksky замечает, что astбиблиотека требует кавычек (либо "или ', даже, """либо ''') вокруг вашего escaped_str, поскольку на самом деле он пытается запустить его как код Python, но повышает безопасность (предотвращает внедрение строк)
InQβ
@ no1xsyzy: Что в случае OP уже имеет место; это правильный ответ , когда strэто reprиз strили bytesобъекта , как в случае с ФП в; unicode-escapeкодек ответ, когда это не repr, но некоторые другие формы сбежавшего текста (не заключены в кавычках как часть самой строки данных).
ShadowRanger
с символами utf-8 это не сработает. оформить последний ответ с пакетом кодов. это действительно работает.
rubmz
FWIW Я пытался разобрать некоторый экранированный текст JSON и продолжал получать эту ошибку, [ERROR] TypeError: string indices must be integersи это решение помогло решить эту проблему. Отмените экранирование строки, затем проанализируйте как JSON.
кибермонах
20

Все данные ответы будут разбиты на общие строки Unicode. Насколько я могу судить, для Python3 во всех случаях работает следующее:

from codecs import encode, decode
sample = u'mon€y\\nröcks'
result = decode(encode(sample, 'latin-1', 'backslashreplace'), 'unicode-escape')
print(result)

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

import ast
sample = u'mon€y\\nröcks'
print(ast.literal_eval(F'"{sample}"'))

Или вот так, когда ваша строка действительно содержит строковый литерал (включая кавычки):

import ast
sample = u'"mon€y\\nröcks"'
print(ast.literal_eval(sample))

Однако, если вы не уверены, используются ли во входной строке двойные или одинарные кавычки в качестве разделителей, или когда вы не можете предположить, что она вообще экранирована должным образом, тогда literal_evalможет некоторое SyntaxErrorвремя повышаться, пока метод кодирования / декодирования все равно будет работать.

Jesko Hüttenhain
источник
ast.literal_eval('"mon€y\\nröcks"') == "mon€y\nröcks"у меня отлично работает с Python 3.7.3
oldrinb
Спасибо за комментарий @oldrinb! Я отредактировал ответ, включив это.
Jesko Hüttenhain,
14

В Python 3 у strобъектов нет decodeметода, и вы должны использовать bytesобъект. Ответ ChristopheD касается python 2.

# create a `bytes` object from a `str`
my_str = "Hello,\\nworld"
# (pick an encoding suitable for your str, e.g. 'latin1')
my_bytes = my_str.encode("utf-8")

# or directly
my_bytes = b"Hello,\\nworld"

print(my_bytes.decode("unicode_escape"))
# "Hello,
# world"
asac
источник
2
Собираем вместе value.encode('utf-8').decode('unicode_escape').
Кейси Кубалл
6
Это, к сожалению, сломается, если строка содержит некоторые символы utf-8, отличные от ascii (то есть польские символы)
Pax0r
Вы пробовали подобрать кодировку, подходящую для полировки при звонке на encode?
ГАГА
с символами utf-8 это не сработает. оформить последний ответ с пакетом кодов. это действительно работает.
rubmz