¿Cómo deshacer el escape de una cadena de escape con barra invertida?

100

Supongamos que tengo una cadena que es una versión de escape con barra invertida de otra cadena. ¿Existe una manera fácil, en Python, de eliminar la cadena? Podría, por ejemplo, hacer:

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

Sin embargo, eso implica pasar una cadena (posiblemente no confiable) a eval () que es un riesgo de seguridad. ¿Existe una función en la biblioteca estándar que toma una cadena y produce una cadena sin implicaciones de seguridad?

Mella
fuente

Respuestas:

137
>>> print '"Hello,\\nworld!"'.decode('string_escape')
"Hello,
world!"
Cristóbal
fuente
9
¿Hay algo que sea compatible con Python 3?
thejinx0r
3
@ thejinx0r: eche un vistazo aquí: stackoverflow.com/questions/14820429/…
ChristopheD
29
Básicamente para Python3 lo que quieresprint(b"Hello,\nworld!".decode('unicode_escape'))
ChristopheD
3
Para Python 3, usevalue.encode('utf-8').decode('unicode_escape')
Casey Kuball
8
ADVERTENCIA: value.encode('utf-8').decode('unicode_escape') corrompe los caracteres no ASCII en la cadena . A menos que se garantice que la entrada solo contiene caracteres ASCII, esta no es una solución válida.
Alex Peters
35

Puede usar ast.literal_evalcuál es seguro:

Evalúe de forma segura un nodo de expresión o una cadena que contenga una expresión de Python. La cadena o nodo proporcionado solo puede constar de las siguientes estructuras literales de Python: cadenas, números, tuplas, listas, dictados, valores booleanos y Ninguno. (FINAL)

Me gusta esto:

>>> import ast
>>> escaped_str = '"Hello,\\nworld!"'
>>> print ast.literal_eval(escaped_str)
Hello,
world!
jatismo
fuente
3
Tener un punto y coma de escape en la cadena rompe este código. Lanza un error de sintaxis "carácter inesperado tras carácter de continuación de línea"
darksky
3
@darksky nota que la astbiblioteca requiere comillas ( "o ', incluso """o ''') alrededor de su escaped_str, ya que en realidad está tratando de ejecutarlo como código Python pero mejora la seguridad (evita la inyección de cadenas)
InQβ
@ no1xsyzy: que en el caso del OP ya es el caso; esta es la respuesta correcta cuando el stres un reprde un objeto stro bytescomo en el caso del OP; la unicode-escaperespuesta del códec es para cuando no es un repr, sino alguna otra forma de texto de escape (no entre comillas como parte de los datos de la cadena).
ShadowRanger
con caracteres utf-8 esto no funcionará. Consulte la última respuesta con el paquete de códigos. realmente funciona.
rubmz
FWIW Estaba intentando analizar un texto JSON escapado y seguía recibiendo este error [ERROR] TypeError: string indices must be integersy esta solución funcionó para resolverlo. Elimine el escape de la cadena y luego analícela como JSON.
cyber-monk hace
20

Todas las respuestas dadas se romperán en cadenas Unicode generales. Lo siguiente funciona para Python3 en todos los casos, por lo que puedo decir:

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

Como se describe en los comentarios, también puede usar el literal_evalmétodo del astmódulo así:

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

O así cuando su cadena realmente contiene un literal de cadena (incluidas las comillas):

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

Sin embargo, si no está seguro de si la cadena de entrada utiliza comillas dobles o simples como delimitadores, o si no puede asumir que se ha escapado correctamente, es literal_evalposible SyntaxErrorque el método de codificación / decodificación siga funcionando durante un tiempo.

Jesko Hüttenhain
fuente
ast.literal_eval('"mon€y\\nröcks"') == "mon€y\nröcks"funciona bien para mí con Python 3.7.3
oldrinb
¡Gracias por el comentario @oldrinb! Edité la respuesta para incluir eso.
Jesko Hüttenhain
14

En Python 3, los strobjetos no tienen un decodemétodo y debes usar un bytesobjeto. La respuesta de ChristopheD cubre 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
fuente
2
Juntando todo, value.encode('utf-8').decode('unicode_escape').
Casey Kuball
6
Lamentablemente, esto se romperá si la cadena contiene algunos caracteres utf-8 no ascii (es decir, caracteres polacos)
Pax0r
¿Ha intentado elegir una codificación adecuada para pulir en la llamada a encode?
asac
con caracteres utf-8 esto no funcionará. Consulte la última respuesta con el paquete de códigos. realmente funciona.
rubmz