Apa sebenarnya yang dilakukan flag string “u” dan “r”, dan apa literal string mentah?

652

Saat mengajukan pertanyaan ini , saya menyadari saya tidak tahu banyak tentang string mentah. Untuk seseorang yang mengaku sebagai pelatih Django, ini menyebalkan.

Saya tahu apa itu pengkodean, dan saya tahu apa yang u''dikerjakan sendiri sejak saya mendapatkan apa itu Unicode.

  • Tapi apa yang sebenarnya r''dilakukan? Apa jenis string yang dihasilkannya?

  • Dan di atas semua, apa yang dilakukan sih ur''?

  • Akhirnya, apakah ada cara yang dapat diandalkan untuk kembali dari string Unicode ke string mentah sederhana?

  • Ah, dan omong-omong, jika sistem Anda dan charset editor teks Anda diatur ke UTF-8, apakah u''benar-benar melakukan sesuatu?

e-satis
sumber

Jawaban:

683

Sebenarnya tidak ada " string mentah "; ada literal string mentah , yang persis literal string ditandai oleh 'r'sebelum kutipan pembukaan.

"Raw string literal" adalah sintaks yang sedikit berbeda untuk string literal, di mana backslash, \dianggap sebagai "hanya backslash" (kecuali ketika muncul tepat sebelum kutipan yang dinyatakan akan mengakhiri literal) - tidak "escape sequence" untuk mewakili baris baru, tab, spasi mundur, umpan formulir, dan sebagainya. Dalam literal string normal, setiap garis miring terbalik harus digandakan untuk menghindari diambil sebagai awal dari urutan pelarian.

Varian sintaksis ini ada sebagian besar karena sintaksis pola ekspresi reguler berat dengan garis miring terbalik (tetapi tidak pernah pada akhirnya, jadi klausa "kecuali" di atas tidak masalah) dan terlihat sedikit lebih baik ketika Anda menghindari penggandaan masing-masing - - itu saja. Itu juga mendapatkan beberapa popularitas untuk mengekspresikan jalur file Windows asli (dengan backslash bukan garis miring biasa seperti pada platform lain), tetapi itu sangat jarang diperlukan (karena garis miring yang normal sebagian besar bekerja dengan baik pada Windows juga) dan tidak sempurna (karena klausa "kecuali" atas).

r'...'adalah string byte (Python 2. *), ur'...'adalah string Unicode (sekali lagi, dengan Python 2. *), dan salah satu dari tiga jenis lain mengutip juga menghasilkan jenis yang sama persis dari string (jadi misalnya r'...', r'''...''', r"...", r"""..."""semua byte string, dan sebagainya).

Tidak yakin apa yang Anda maksud dengan " kembali " - tidak ada arah intrinsik maju dan mundur, karena tidak ada jenis string mentah , itu hanya sintaks alternatif untuk mengekspresikan objek string normal, byte atau unicode.

Dan ya, di Python 2. *, u'...' adalah tentu saja selalu berbeda dari hanya '...'- yang pertama adalah string unicode, yang terakhir adalah string byte. Pengkodean literal apa yang mungkin diekspresikan adalah masalah yang sepenuhnya ortogonal.

Misalnya, pertimbangkan (Python 2.6):

>>> sys.getsizeof('ciao')
28
>>> sys.getsizeof(u'ciao')
34

Objek Unicode tentu saja membutuhkan lebih banyak ruang memori (perbedaan sangat kecil untuk string yang sangat pendek, jelas ;-).

Alex Martelli
sumber
6
Memahami "r" tidak menyiratkan jenis atau masalah penyandian, itu jauh lebih sederhana.
e-satis
23
Perhatikan bahwa ru "C: \ foo \ unstable" akan gagal karena \ u adalah urutan pelepasan unicode dalam mode ru. Mode r tidak memiliki \ u.
Curtis Yallop
26
Perhatikan bahwa udan rtidak komutatif: ur'str'berfungsi, ru'str'tidak. (setidaknya dalam ipython 2.7.2 pada win7)
RafiK
7
Hanya menguji rstring dan memperhatikan bahwa jika \ karakter terakhir itu tidak akan dianggap sebagai literal melainkan lolos dari kutipan penutup, menyebabkan SyntaxError: EOL while scanning string literal. Jadi \\ masih harus digunakan untuk contoh terakhir \ dalam string yang diakhiri dengan garis miring terbalik.
Enteleform
1
python 3.x - sys.getsizeof('cioa') == sys.getsizeof(r'cioa') == sys.getsizeof(u'cioa')(Ubuntu 16.04 dengan UTF8 lang). Demikian pula type('cioa') == type(r'cioa') == type(u'cioa'),. TETAPI, interpolasi string mentah membuat perbedaan, jadisys.getsizeof('\ncioa') == sys.getsizeof(u'\ncioa') != sys.getsizeof(r'\ncioa')
Darren Weber
177

Ada dua jenis string dalam python: strtipe tradisional dan tipe yang lebih baru unicode. Jika Anda mengetikkan string literal tanpa udi depan Anda mendapatkan strtipe lama yang menyimpan 8-bit karakter, dan dengan udi depan Anda mendapatkan unicodetipe yang lebih baru yang dapat menyimpan karakter Unicode.

The rtidak mengubah jenis sama sekali, itu hanya mengubah cara literal string ditafsirkan. Tanpa itu r, garis miring terbalik diperlakukan sebagai karakter pelarian. Dengan itu r, garis miring terbalik diperlakukan sebagai literal. Either way, tipenya sama.

ur tentu saja merupakan string Unicode di mana garis miring terbalik adalah garis miring terbalik literal, bukan bagian dari kode pelarian.

Anda dapat mencoba mengonversi string Unicode ke string lama menggunakan str()fungsi, tetapi jika ada karakter unicode yang tidak dapat direpresentasikan dalam string lama, Anda akan mendapatkan pengecualian. Anda dapat menggantinya dengan tanda tanya terlebih dahulu jika diinginkan, tetapi tentu saja ini akan menyebabkan karakter tersebut tidak dapat dibaca. Tidak disarankan untuk menggunakan strtipe ini jika Anda ingin menangani karakter unicode dengan benar.

Mark Byers
sumber
Terima kasih, diterima. Seperti yang saya katakan, saya tahu apa itu unicode, saya tidak tahu apa arti "r" dan apa kombinasi dari "u" dan "r". Saya tahu lebih baik, bersorak.
e-satis
6
Garis miring terbalik tidak diperlakukan sebagai literal dalam literal string mentah, yang merupakan r"\"kesalahan sintaksis.
4
Hanya berlaku untuk Python 2.
PaulMcG
60

'string mentah' berarti disimpan ketika muncul. Misalnya, '\'hanya backslash bukan pelarian .

Xiaolong
sumber
3
... kecuali itu karakter terakhir dari string, dalam hal ini tidak lolos dari kutipan penutup.
jez
36

Awalan "u" menunjukkan nilai bertipe unicodebukan str.

Literal string mentah, dengan awalan "r", lolos dari urutan escape apa pun di dalamnya, demikian len(r"\n")juga 2. Karena mereka keluar dari sequence escape, Anda tidak dapat mengakhiri string string dengan backslash tunggal: itu bukan urutan escape yang valid (misalnya r"\").

"Raw" bukan bagian dari tipe, itu hanya satu cara untuk mewakili nilai. Sebagai contoh, "\\n"dan r"\n"nilai-nilai yang identik, seperti 32, 0x20, dan 0b100000adalah identik.

Anda dapat memiliki unicode literal string baku:

>>> u = ur"\n"
>>> print type(u), len(u)
<type 'unicode'> 2

Pengkodean file sumber hanya menentukan cara menafsirkan file sumber, itu tidak mempengaruhi ekspresi atau jenis sebaliknya. Namun, disarankan untuk menghindari kode tempat penyandian selain ASCII akan mengubah artinya:

File yang menggunakan ASCII (atau UTF-8, untuk Python 3.0) tidak boleh memiliki cookie pengodean. Latin-1 (atau UTF-8) hanya boleh digunakan ketika komentar atau dokumen perlu menyebutkan nama penulis yang membutuhkan Latin-1; jika tidak, menggunakan \ x, \ u atau \ U lolos adalah cara yang disukai untuk memasukkan data non-ASCII dalam string literal.


sumber
30

Biarkan saya jelaskan secara sederhana: Dalam python 2, Anda dapat menyimpan string dalam 2 jenis berbeda.

Yang pertama adalah ASCII yang bertipe str dalam python, menggunakan memori 1 byte. (256 karakter, sebagian besar akan menyimpan huruf Inggris dan simbol sederhana)

Tipe 2 adalah UNICODE yang merupakan tipe unicode dalam python. Unicode menyimpan semua jenis bahasa.

Secara default, python akan lebih memilih tipe str tetapi jika Anda ingin menyimpan string dalam tipe unicode Anda dapat menempatkan Anda di depan teks seperti u'text ' atau Anda dapat melakukan ini dengan memanggil unicode (' text ')

Jadi kamu hanyalah cara singkat untuk memanggil fungsi untuk melemparkan str ke unicode . Itu dia!

Sekarang bagian r , Anda meletakkannya di depan teks untuk memberi tahu komputer bahwa teks tersebut adalah teks mentah, garis miring terbalik seharusnya bukan karakter yang melarikan diri. r '\ n' tidak akan membuat karakter baris baru. Hanya saja teks biasa berisi 2 karakter.

Jika Anda ingin mengonversi str ke unicode dan juga memasukkan teks mentah di sana, gunakan ur karena ru akan memunculkan kesalahan.

SEKARANG, bagian penting:

Anda tidak dapat menyimpan satu backslash dengan menggunakan r , itu satu-satunya pengecualian. Jadi kode ini akan menghasilkan kesalahan: r '\'

Untuk menyimpan garis miring terbalik (hanya satu), Anda perlu menggunakan '\\'

Jika Anda ingin menyimpan lebih dari 1 karakter Anda masih dapat menggunakan r seperti r '\\' akan menghasilkan 2 garis miring terbalik seperti yang Anda harapkan.

Saya tidak tahu alasan mengapa r tidak bekerja dengan satu penyimpanan backslash tetapi alasannya belum dijelaskan oleh siapa pun. Saya harap ini adalah bug.

off99555
sumber
9
Anda akan melihat tidak hanya r'\'ilegal, Anda bahkan tidak dapat menempatkan satu '\'ekor pun. Sama seperti r'xxxxxx\'string ilegal.
penyelam
bagaimana dengan python 3?
Krissh
1
@ Krissh Semua string python 3 didukung Unicode. Jenisnya akan str. Baca lebih lanjut untuk pemahaman yang lebih baik di sini: medium.com/better-programming/…
off99555
4

Mungkin ini jelas, mungkin tidak, tetapi Anda dapat membuat string '\' dengan memanggil x = chr (92)

x=chr(92)
print type(x), len(x) # <type 'str'> 1
y='\\'
print type(y), len(y) # <type 'str'> 1
x==y   # True
x is y # False
Bomba Ps
sumber
4
x is ymengevaluasi ke True di python3?
Habeeb Perwad
5
@HabeebPerwad, itu karena string interning . Anda tidak boleh mengandalkan fakta yang x is yterjadi untuk dievaluasi Truekarena magang. Alih-alih menggunakan x == y(jika Anda tidak memeriksa apakah x dan y adalah objek yang sama persis disimpan pada satu posisi memori, yaitu).
Lucubrator
4

Literal string unicode

Literal string Unicode (string literal diawali oleh u) tidak lagi digunakan dalam Python 3. Mereka masih valid tetapi hanya untuk tujuan kompatibilitas dengan Python 2.

Literal string mentah

Jika Anda ingin membuat string literal terdiri dari hanya karakter mudah typable seperti huruf bahasa Inggris atau angka, Anda cukup mengetik mereka: 'hello world'. Tetapi jika Anda ingin memasukkan juga beberapa karakter yang lebih eksotis, Anda harus menggunakan beberapa solusi. Salah satu solusinya adalah urutan Escape . Dengan cara ini misalnya Anda dapat mewakili baris baru di string Anda hanya dengan menambahkan dua karakter yang mudah diketik \nke string literal Anda. Jadi ketika Anda mencetak 'hello\nworld'string, kata-kata akan dicetak pada baris yang berbeda. Itu sangat berguna!

Di sisi lain, ada beberapa situasi ketika Anda ingin membuat string literal yang berisi urutan melarikan diri tetapi Anda tidak ingin mereka ditafsirkan oleh Python. Anda ingin mereka mentah . Lihatlah contoh-contoh ini:

'New updates are ready in c:\windows\updates\new'
'In this lesson we will learn what the \n escape sequence does.'

Dalam situasi seperti itu Anda hanya bisa mengawali string literal dengan rkarakter seperti ini: r'hello\nworld'dan tidak ada urutan pelarian yang akan ditafsirkan oleh Python. Tali akan dicetak persis seperti yang Anda buat.

Literal string mentah tidak sepenuhnya "mentah"?

Banyak orang berharap string string literal menjadi mentah dalam arti bahwa "apa pun yang ditempatkan di antara tanda kutip diabaikan oleh Python" . Itu tidak benar. Python masih mengenali semua urutan pelarian, itu hanya tidak menafsirkannya - itu membuat mereka tidak berubah sebagai gantinya. Ini berarti bahwa literal string baku masih harus literal string yang valid .

Dari definisi leksikal string literal:

string     ::=  "'" stringitem* "'"
stringitem ::=  stringchar | escapeseq
stringchar ::=  <any source character except "\" or newline or the quote>
escapeseq  ::=  "\" <any source character>

Jelas bahwa string literal (mentah atau tidak) yang mengandung karakter kutipan telanjang: 'hello'world'atau diakhiri dengan garis miring terbalik: 'hello world\'tidak valid.

Jeyekomon
sumber