Comment annuler l'échappement d'une chaîne échappée par une barre oblique inverse?

101

Supposons que j'ai une chaîne qui est une version échappée par une barre oblique inverse d'une autre chaîne. Existe-t-il un moyen simple, en Python, de faire disparaître la chaîne? Je pourrais, par exemple, faire:

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

Cependant, cela implique de passer une chaîne (peut-être non approuvée) à eval (), ce qui représente un risque pour la sécurité. Y a-t-il une fonction dans la bibliothèque standard qui prend une chaîne et produit une chaîne sans implication de sécurité?

pseudo
la source

Réponses:

138
>>> print '"Hello,\\nworld!"'.decode('string_escape')
"Hello,
world!"
ChristopheD
la source
9
Y a-t-il quelque chose de compatible avec Python 3?
thejinx0r
3
@ thejinx0r: jetez un oeil ici: stackoverflow.com/questions/14820429/…
ChristopheD
30
En gros pour Python3 que vous voulezprint(b"Hello,\nworld!".decode('unicode_escape'))
ChristopheD
3
Pour python 3, utilisezvalue.encode('utf-8').decode('unicode_escape')
Casey Kuball
8
AVERTISSEMENT: value.encode('utf-8').decode('unicode_escape') corrompt les caractères non ASCII de la chaîne . À moins que l'entrée ne contienne uniquement des caractères ASCII, ce n'est pas une solution valide.
Alex Peters
35

Vous pouvez utiliser ast.literal_evalce qui est sûr:

Évaluez en toute sécurité un nœud d'expression ou une chaîne contenant une expression Python. La chaîne ou le nœud fourni ne peut être constitué que des structures littérales Python suivantes: chaînes, nombres, tuples, listes, dictionnaires, booléens et None. (FIN)

Comme ça:

>>> import ast
>>> escaped_str = '"Hello,\\nworld!"'
>>> print ast.literal_eval(escaped_str)
Hello,
world!
jathanisme
la source
3
Avoir un point-virgule échappé dans la chaîne casse ce code. Lance une erreur de syntaxe "caractère inattendu après le caractère de continuation de ligne"
sombre
3
@darksky remarque que la astbibliothèque nécessite des guillemets (soit "ou ', même """ou ''') autour de votre escaped_str, car elle essaie en fait de l'exécuter en tant que code Python mais améliore la sécurité (empêche l'injection de chaîne)
InQβ
@ no1xsyzy: Ce qui dans le cas de l'OP est déjà le cas; c'est la bonne réponse lorsque le strest un reprd'un objet strou bytescomme dans le cas de l'OP; la unicode-escaperéponse du codec est pour quand ce n'est pas un repr, mais une autre forme de texte échappé (non entouré de guillemets dans le cadre des données de chaîne elles-mêmes).
ShadowRanger
avec les caractères utf-8, cela ne fonctionnera pas. vérifier la dernière réponse avec le paquet de codes. cela fonctionne réellement.
rubmz
FWIW J'essayais d'analyser du texte JSON échappé et continuais à obtenir cette erreur [ERROR] TypeError: string indices must be integerset cette solution a fonctionné pour résoudre ce problème. Annulez l'échappement de la chaîne, puis analysez-la comme JSON.
cyber-monk
20

Toutes les réponses données seront interrompues sur les chaînes Unicode générales. Ce qui suit fonctionne pour Python3 dans tous les cas, pour autant que je sache:

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

Comme indiqué dans les commentaires, vous pouvez également utiliser la literal_evalméthode du astmodule comme suit:

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

Ou comme ceci lorsque votre chaîne contient vraiment une chaîne littérale (y compris les guillemets):

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

Cependant, si vous ne savez pas si la chaîne d'entrée utilise des guillemets doubles ou simples comme délimiteurs, ou si vous ne pouvez pas du tout supposer qu'elle est correctement échappée, la méthode d'encodage / décodage fonctionnera peut-être encore literal_evalun SyntaxErrorcertain temps.

Jesko Hüttenhain
la source
ast.literal_eval('"mon€y\\nröcks"') == "mon€y\nröcks"fonctionne bien pour moi avec Python 3.7.3
oldrinb
Merci pour le commentaire @oldrinb! J'ai modifié la réponse pour l'inclure.
Jesko Hüttenhain
14

En python 3, les strobjets n'ont pas de decodeméthode et vous devez utiliser un bytesobjet. La réponse de ChristopheD couvre 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
la source
2
Mettre ensemble, value.encode('utf-8').decode('unicode_escape').
Casey Kuball
6
Cela va malheureusement casser si la chaîne contient des caractères utf-8 non-ascii (c'est-à-dire des caractères polonais)
Pax0r
Avez-vous essayé de choisir un encodage adapté au polissage dans l'appel à encode?
asac
avec les caractères utf-8, cela ne fonctionnera pas. vérifier la dernière réponse avec le paquet de codes. cela fonctionne réellement.
rubmz le