A veces, cuando obtengo información de un archivo o del usuario, obtengo una cadena con secuencias de escape. Me gustaría procesar las secuencias de escape de la misma manera que Python procesa las secuencias de escape en cadenas literales .
Por ejemplo, digamos que myString
se define como:
>>> myString = "spam\\neggs"
>>> print(myString)
spam\neggs
Quiero una función (la llamaré process
) que haga esto:
>>> print(process(myString))
spam
eggs
Es importante que la función pueda procesar todas las secuencias de escape en Python (enumeradas en una tabla en el enlace de arriba).
¿Python tiene una función para hacer esto?
'spam'+"eggs"+'''some'''+"""more"""
procesara una cadena que contiene ?myString = "'spam'+\"eggs\"+'''some'''+\"\"\"more\"\"\""
,print(bytes(myString, "utf-8").decode("unicode_escape"))
parece funcionar.Respuestas:
Lo correcto es usar el código 'string-escape' para decodificar la cadena.
No use AST o eval. Usar los códecs de cadena es mucho más seguro.
fuente
'string\W+escape'
Notice that spelling alternatives that only differ in case or use a hyphen instead of an underscore are also valid aliases; therefore, e.g. 'utf-8' is a valid alias for the 'utf_8' codec.
>>> print("juancarlo\\tañez".encode('utf-8').decode('unicode_escape'))
obtienes:juancarlo añez
latin1
es asumido porunicode_escape
,s.encode('utf-8').decode('unicode_escape').encode('latin1').decode('utf8')
unicode_escape
no funciona en generalResulta que la solución
string_escape
ounicode_escape
no funciona en general; en particular, no funciona en presencia de Unicode real.Si puede estar seguro de que todos los caracteres que no sean ASCII se escaparán (y recuerde, cualquier cosa más allá de los primeros 128 caracteres no es ASCII),
unicode_escape
hará lo correcto por usted. Pero si ya hay caracteres literales no ASCII en su cadena, las cosas saldrán mal.unicode_escape
está diseñado fundamentalmente para convertir bytes en texto Unicode. Pero en muchos lugares, por ejemplo, el código fuente de Python, los datos de origen ya son texto Unicode.La única forma en que esto puede funcionar correctamente es si primero codifica el texto en bytes. UTF-8 es la codificación sensata para todo el texto, así que debería funcionar, ¿verdad?
Los siguientes ejemplos están en Python 3, por lo que los literales de cadena son más limpios, pero existe el mismo problema con manifestaciones ligeramente diferentes en Python 2 y 3.
Bueno, eso está mal.
La nueva forma recomendada de utilizar códecs que decodifican texto en texto es llamar
codecs.decode
directamente. ¿Eso ayuda?De ningún modo. (Además, lo anterior es un UnicodeError en Python 2.)
El
unicode_escape
códec, a pesar de su nombre, asume que todos los bytes que no son ASCII están en la codificación Latin-1 (ISO-8859-1). Entonces tendrías que hacerlo así:Pero eso es terrible. Esto lo limita a los 256 caracteres Latin-1, ¡como si Unicode nunca se hubiera inventado!
Agregar una expresión regular para resolver el problema
(Sorprendentemente, ahora no tenemos dos problemas).
Lo que tenemos que hacer es aplicar el
unicode_escape
decodificador solo a cosas que estamos seguros de que serán texto ASCII. En particular, podemos asegurarnos de aplicarlo solo a secuencias de escape de Python válidas, que están garantizadas como texto ASCII.El plan es que encontraremos secuencias de escape usando una expresión regular y usaremos una función como argumento
re.sub
para reemplazarlas con su valor sin escape.Y con eso:
fuente
os.sep
en absoluto? Estoy tratando de hacer esto:patt = '^' + self.prefix + os.sep ; name = sub(decode_escapes(patt), '', name)
y no funciona. El punto y coma está allí en lugar de una nueva línea.os.sep
es tuyo ?). Si tienes secuencias de escape con barra invertida en los nombres de los directorios de Windows, la situación es prácticamente irrecuperable.La respuesta realmente correcta y conveniente para Python 3:
Detalles sobre
codecs.escape_decode
:codecs.escape_decode
es un decodificador de bytes a bytescodecs.escape_decode
decodifica secuencias de escape ascii, como:b"\\n"
->b"\n"
,b"\\xce"
->b"\xce"
.codecs.escape_decode
no le importa ni necesita saber acerca de la codificación del objeto byte, pero la codificación de los bytes escapados debe coincidir con la codificación del resto del objeto.Antecedentes:
unicode_escape
es la solución incorrecta para python3. Esto se debe a queunicode_escape
decodifica los bytes de escape, luego decodifica los bytes en una cadena Unicode, pero no recibe información sobre qué códec usar para la segunda operación.codecs.escape_decode
partir de esta respuesta a "¿cómo puedo .decode ('string-escape') en Python3?" . Como dice esa respuesta, esa función actualmente no está documentada para Python 3.fuente
\x
escapes de bytes UTF-8. Pero debido a que decodifica bytes a bytes, no decodifica, y no puede, los escapes de caracteres Unicode que no son ASCII, como los\u
escapes.La
ast.literal_eval
función se acerca, pero espera que la cadena se cite correctamente primero.Por supuesto, la interpretación de Python de los escapes de barra invertida depende de cómo se cite la cadena (
""
vsr""
vsu""
, comillas triples, etc.) por lo que es posible que desee envolver la entrada del usuario entre comillas adecuadas y pasar aliteral_eval
. Envolverlo entre comillas también evitará que seliteral_eval
devuelva un número, tupla, diccionario, etc.Las cosas aún pueden complicarse si el usuario escribe comillas sin comillas del tipo que pretende envolver alrededor de la cadena.
fuente
myString = "\"\ndoBadStuff()\n\""
,print(ast.literal_eval('"' + myString + '"'))
parece intentar ejecutar código. ¿Cómo esast.literal_eval
diferente / más seguro queeval
?literal_eval
nunca ejecuta código. De la documentación, "Esto se puede utilizar para evaluar de forma segura cadenas que contienen expresiones de Python de fuentes no confiables sin la necesidad de analizar los valores por sí mismo".Esta es una mala forma de hacerlo, pero funcionó para mí cuando intentaba interpretar octals escapados pasados en un argumento de cadena.
Vale la pena mencionar que hay una diferencia entre eval y ast.literal_eval (eval es mucho más inseguro). Ver ¿ Usar eval () de python frente a ast.literal_eval ()?
fuente
El siguiente código debería funcionar para \ n es necesario que se muestre en la cadena.
fuente
replace
que no se haga nada), utiliza API muy desactualizadas (lasstring
funciones del módulo de este tipo están obsoletas a partir de Python 2.0, reemplazadas por losstr
métodos y desaparecieron por completo en Python 3), y solo maneja el caso específico de reemplazar una sola línea nueva, no el procesamiento de escape general.