Bagaimana cara melepaskan string backslash-escaped?

100

Misalkan saya memiliki string yang merupakan versi backslash-escape dari string lain. Adakah cara mudah, dengan Python, untuk melepaskan string? Saya bisa, misalnya, melakukan:

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

Namun itu melibatkan penerusan string (mungkin tidak tepercaya) ke eval () yang merupakan risiko keamanan. Apakah ada fungsi dalam lib standar yang mengambil string dan menghasilkan string tanpa implikasi keamanan?

Nick
sumber

Jawaban:

137
>>> print '"Hello,\\nworld!"'.decode('string_escape')
"Hello,
world!"
ChristopheD
sumber
9
Apakah ada sesuatu yang kompatibel dengan python 3?
thejinx0r
3
@ thejinx0r: lihat di sini: stackoverflow.com/questions/14820429/…
ChristopheD
29
Pada dasarnya untuk Python3 yang Anda inginkanprint(b"Hello,\nworld!".decode('unicode_escape'))
ChristopheD
3
Untuk python 3, gunakanvalue.encode('utf-8').decode('unicode_escape')
Casey Kuball
8
PERINGATAN: value.encode('utf-8').decode('unicode_escape') merusak karakter non-ASCII dalam string . Kecuali jika masukan dijamin hanya berisi karakter ASCII, ini bukan solusi yang valid.
Alex Peters
35

Anda dapat menggunakan ast.literal_evalyang aman:

Mengevaluasi node ekspresi atau string yang berisi ekspresi Python dengan aman. String atau node yang disediakan hanya boleh terdiri dari struktur literal Python berikut: string, numbers, tuple, list, dicts, boolean, dan None. (AKHIR)

Seperti ini:

>>> import ast
>>> escaped_str = '"Hello,\\nworld!"'
>>> print ast.literal_eval(escaped_str)
Hello,
world!
jatanisme
sumber
3
Memiliki titik koma yang lolos dalam string memecah kode ini. Melempar kesalahan sintaks "karakter tak terduga setelah karakter kelanjutan baris"
darksky
3
@darksky perhatikan bahwa astpustaka memerlukan tanda kutip (baik "atau ', genap """atau ''') di sekitar escaped_str Anda, karena ia sebenarnya mencoba menjalankannya sebagai kode Python tetapi meningkatkan keamanan (mencegah injeksi string)
InQβ
@ no1xsyzy: Yang mana dalam kasus OP sudah terjadi; ini adalah jawaban yang benar jika stradalah a reprdari a stratau bytesobjek seperti dalam kasus OP; yang unicode-escapejawabannya codec adalah ketika itu bukan repr, tapi beberapa bentuk lain dari teks lolos (tidak dikelilingi oleh tanda kutip sebagai bagian dari data string itu sendiri).
ShadowRanger
dengan utf-8 chars ini tidak akan bekerja. checkout jawaban terakhir dengan paket kode. itu benar-benar bekerja.
rubmz
FWIW Saya mencoba mengurai beberapa teks JSON yang lolos dan terus mendapatkan kesalahan [ERROR] TypeError: string indices must be integersini dan solusi ini berhasil menyelesaikannya. Hapus stringnya, lalu parsing sebagai JSON.
biksu cyber
20

Semua jawaban yang diberikan akan rusak pada string Unicode umum. Berikut ini berfungsi untuk Python3 dalam semua kasus, sejauh yang saya tahu:

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

Seperti yang diuraikan dalam komentar, Anda juga dapat menggunakan literal_evalmetode dari astmodul seperti:

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

Atau seperti ini ketika string Anda benar - benar berisi string literal (termasuk tanda kutip):

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

Namun, jika Anda tidak yakin apakah string input menggunakan tanda kutip ganda atau tunggal sebagai pembatas, atau jika Anda tidak dapat mengasumsikannya untuk di-escape sama sekali, literal_evalmungkin perlu waktu SyntaxErrorlama metode encode / decode akan tetap berfungsi.

Jesko Hüttenhain
sumber
ast.literal_eval('"mon€y\\nröcks"') == "mon€y\nröcks"berfungsi dengan baik untuk saya dengan Python 3.7.3
oldrinb
Terima kasih atas komentar @oldrinb! Saya mengedit jawabannya untuk memasukkan itu.
Jesko Hüttenhain
14

Di python 3, strobjek tidak memiliki decodemetode dan Anda harus menggunakan bytesobjek. Jawaban ChristopheD mencakup 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
sumber
2
Menyatukannya value.encode('utf-8').decode('unicode_escape'),.
Casey Kuball
6
Sayangnya ini akan rusak jika string berisi beberapa karakter utf-8 non-ascii (yaitu karakter Polandia)
Pax0r
Sudahkah Anda mencoba memilih pengkodean yang cocok untuk dipoles dalam panggilan ke encode?
asac
dengan utf-8 chars ini tidak akan bekerja. checkout jawaban terakhir dengan paket kode. itu benar-benar bekerja.
rubmz