Cosa fanno esattamente i flag di stringa “u” e “r” e cosa sono i letterali di stringa grezzi?


652

Durante questa domanda facevo , mi sono reso conto che non sapevo molto delle stringhe grezze. Per qualcuno che afferma di essere un allenatore di Django, questo fa schifo.

So cos'è una codifica e so cosa u''fa da solo poiché ottengo ciò che è Unicode.

  • Ma cosa fa r''esattamente? In che tipo di stringa risulta?

  • E soprattutto, che diamine fa ur''?

  • Infine, esiste un modo affidabile per tornare da una stringa Unicode a una semplice stringa non elaborata?

  • Ah, e comunque, se il tuo sistema e il tuo set di caratteri dell'editor di testo sono impostati su UTF-8, fa u''davvero qualcosa?

Risposte:


683

Non c'è davvero nessuna " stringa grezza "; ci sono letterali stringa grezzi , che sono esattamente i letterali stringa contrassegnati da un 'r'prima della citazione di apertura.

Una "stringa letterale non elaborata" è una sintassi leggermente diversa per una stringa letterale, in cui una barra rovesciata, \ viene considerata come "solo una barra rovesciata" (tranne quando si trova proprio prima di una citazione che altrimenti terminerebbe la lettera) - no "escape sequences" per rappresentare newline, tab, backspaces, form feed e così via. Nei normali valori letterali di stringa, ogni barra rovesciata deve essere raddoppiata per evitare di essere presa come inizio di una sequenza di escape.

Questa variante di sintassi esiste principalmente perché la sintassi dei modelli di espressioni regolari è pesante con barre rovesciate (ma mai alla fine, quindi la clausola "tranne" sopra non ha importanza) e sembra un po 'meglio quando eviti di raddoppiare ognuna di esse - - È tutto. Ha anche guadagnato un po 'di popolarità per esprimere i percorsi dei file nativi di Windows (con barre rovesciate anziché normali barre come su altre piattaforme), ma ciò è molto raramente necessario (poiché le barre normali funzionano principalmente anche su Windows) e imperfetto (a causa della clausola "tranne" sopra).

r'...'è una stringa di byte (in Python 2. *), ur'...'è una stringa Unicode (di nuovo, in Python 2. *), e qualsiasi degli altri tre tipi di citare produce esattamente gli stessi tipi di stringhe (così per esempio r'...', r'''...''', r"...", r"""..."""sono tutte stringhe di byte e così via).

Non sono sicuro di cosa intendi per "tornare indietro ": non esistono direzioni intrinsecamente avanti e indietro, poiché non esiste un tipo di stringa non elaborato , è solo una sintassi alternativa per esprimere oggetti stringa, byte o unicode perfettamente normali come potrebbero essere.

E sì, in Python 2. *, ovviamente , u'...' è sempre distinto dal solo '...': il primo è una stringa unicode, il secondo è una stringa di byte. Ciò che codifica il letterale potrebbe essere espresso in una questione completamente ortogonale.

Ad esempio, considera (Python 2.6):

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

L'oggetto Unicode ovviamente occupa più spazio di memoria (una differenza molto piccola per una stringa molto corta, ovviamente ;-).


6
Comprendere "r" non implica alcun tipo o problemi di codifica, è molto più semplice.
e-soddisfa il

23
Nota che ru "C: \ foo \ unstable" fallirà perché \ u è una sequenza di escape unicode in modalità ru. La modalità r non ha \ u.
Curtis Yallop,

26
Si noti che ue rnon sono commutativi: ur'str'funziona, no ru'str'. (almeno in ipython 2.7.2 su win7)
RafiK il

7
Ho appena provato le rstringhe e \ ho notato che se è l'ultimo carattere non verrà preso come un valore letterale ma sfugge invece alla citazione di chiusura, causando SyntaxError: EOL while scanning string literal. Quindi \\ deve ancora essere usato per l'istanza finale di \ qualsiasi stringa che termina con una barra rovesciata.
Enteleform

1
python 3.x - sys.getsizeof('cioa') == sys.getsizeof(r'cioa') == sys.getsizeof(u'cioa')(Ubuntu 16.04 con lang UTF8). Analogamente, type('cioa') == type(r'cioa') == type(u'cioa'). MA, l'interpolazione di stringa non elaborata fa la differenza, quindisys.getsizeof('\ncioa') == sys.getsizeof(u'\ncioa') != sys.getsizeof(r'\ncioa')
Darren Weber,

177

Esistono due tipi di stringhe in Python: il strtipo tradizionale e il più recenteunicode tipo . Se si digita una stringa letterale senza la parte uanteriore, si ottiene il vecchio strtipo che memorizza i caratteri a 8 bit e con la parte uanteriore si ottiene il unicodetipo più recente che può memorizzare qualsiasi carattere Unicode.

Il r non cambia il tipo a tutti, cambia solo il modo letterale stringa viene interpretata. Senza il r, le barre rovesciate vengono trattate come caratteri di escape. Con le rbarre rovesciate vengono considerate letterali. In entrambi i casi, il tipo è lo stesso.

ur è ovviamente una stringa Unicode in cui le barre rovesciate sono letterali barre rovesciate, non parte dei codici di escape.

Puoi provare a convertire una stringa Unicode in una vecchia stringa usando la str()funzione, ma se ci sono caratteri unicode che non possono essere rappresentati nella vecchia stringa, otterrai un'eccezione. Se lo desideri, potresti sostituirli prima con punti interrogativi, ma ovviamente ciò renderebbe illeggibili quei personaggi. Non è consigliabile utilizzare il strtipo se si desidera gestire correttamente i caratteri Unicode.


Grazie, accettato Come ho detto, sapevo cos'è l'unicode, non sapevo cosa significasse "r" e quale sarebbe stata la combinazione di "u" e "r". Conosco meglio, evviva.
e-soddisfa il

6
Le barre rovesciate non vengono considerate letterali nei valori letterali di stringa non elaborati, motivo per cui si r"\"tratta di un errore di sintassi.

4
Si applica solo a Python 2.
PaulMcG

60

'stringa non elaborata' significa che è memorizzata come appare. Ad esempio, '\'è solo una barra rovesciata anziché una fuga .


3
... a meno che non sia l'ultimo carattere della stringa, nel qual caso sfugge alla citazione di chiusura.
jez,

36

Un prefisso "u" indica che il valore ha tipo unicodeanziché str.

I letterali di stringa grezzi, con un prefisso "r", sfuggono a qualsiasi sequenza di escape al loro interno, quindi len(r"\n")è 2. Poiché sfuggono alle sequenze di escape, non è possibile terminare un letterale di stringa con una singola barra rovesciata: non è una sequenza di escape valida (ad es r"\".).

"Raw" non fa parte del tipo, è semplicemente un modo per rappresentare il valore. Ad esempio, "\\n"e r"\n"sono identici valori, come 32, 0x20e 0b100000sono identici.

Puoi avere letterali stringa grezzi unicode:

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

La codifica del file di origine determina solo come interpretare il file di origine, altrimenti non influisce su espressioni o tipi. Tuttavia, si consiglia di evitare il codice in cui una codifica diversa da ASCII cambierebbe il significato:

I file che utilizzano ASCII (o UTF-8, per Python 3.0) non devono avere un cookie di codifica. Il Latin-1 (o UTF-8) dovrebbe essere usato solo quando un commento o un documento deve menzionare un nome di autore che richiede Latin-1; in caso contrario, l'utilizzo di escape \ x, \ u o \ U è il modo preferito per includere dati non ASCII nei letterali di stringa.


30

Permettetemi di spiegarlo semplicemente: in Python 2, è possibile memorizzare la stringa in 2 tipi diversi.

Il primo è ASCII che è di tipo str in Python, utilizza 1 byte di memoria. (256 caratteri, memorizzerà principalmente alfabeti inglesi e simboli semplici)

Il 2o tipo è UNICODE, che è il tipo unicode in Python. Unicode memorizza tutti i tipi di lingue.

Per impostazione predefinita, python preferirà str tipo, ma se si vuole stringa di conservare in unicode tipo si può mettere u davanti al testo come u'text' o si può fare questo chiamando unicode ( 'testo')

Quindi u è solo un modo breve per chiamare una funzione a getto str a unicode . Questo è tutto!

Ora la parte r , la metti davanti al testo per dire al computer che il testo è un testo non elaborato, la barra rovesciata non dovrebbe essere un carattere in fuga. r '\ n' non creerà un nuovo carattere di linea. È solo testo semplice contenente 2 caratteri.

Se vuoi convertire str in unicode e inserire anche del testo non elaborato , usa ur perché ru genererà un errore.

ORA, la parte importante:

Non è possibile memorizzare una barra rovesciata utilizzando r , è l'unica eccezione. Quindi questo codice produrrà errore: r '\'

Per memorizzare una barra rovesciata (solo una) è necessario utilizzare '\\'

Se vuoi memorizzare più di 1 carattere, puoi comunque usare r come r '\\' produrrà 2 barre rovesciate come previsto.

Non conosco il motivo per cui r non funziona con una memoria backslash ma il motivo non è ancora stato descritto da nessuno. Spero che sia un bug.


9
Noterai che non solo r'\'è illegale, ma non puoi nemmeno metterne uno '\'alla coda. Proprio come r'xxxxxx\'una stringa illegale.
divergente il

che dire di python 3?
Krissh,

1
@Krissh Tutte le stringhe di Python 3 sono supportate Unicode. Il suo tipo sarà str. Maggiori informazioni per una migliore comprensione qui: medium.com/better-programming/…
off99555

4

Forse questo è ovvio, forse no, ma puoi creare la stringa '\' chiamando 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

4
x is yrestituisce True in python3?
Habeeb Perwad,

5
@HabeebPerwad, a causa dell'internazionalizzazione delle stringhe . Non dovresti mai fare affidamento sul fatto che x is ycapita di valutare a Truecausa del interning. Invece usa x == y(se non stai verificando se xey sono esattamente lo stesso oggetto archiviato in una singola posizione di memoria, cioè).
Lucubrator,

4

Letterali stringa Unicode

I letterali stringa Unicode (letterali stringa preceduti da u) non sono più utilizzati in Python 3. Sono ancora validi ma solo a fini di compatibilità con Python 2.

Letterali stringa grezzi

Se si desidera creare una stringa letterale composto da soli caratteri facilmente tipizzabili come lettere inglesi o numeri, si può semplicemente digitare: 'hello world'. Ma se vuoi includere anche alcuni personaggi più esotici, dovrai usare qualche soluzione alternativa. Una delle soluzioni alternative sono le sequenze di escape . In questo modo puoi ad esempio rappresentare una nuova riga nella tua stringa semplicemente aggiungendo due caratteri facilmente digitabili \nalla tua stringa letterale. Pertanto, quando si stampa la 'hello\nworld'stringa, le parole verranno stampate su righe separate. È molto utile!

D'altra parte, ci sono alcune situazioni in cui si desidera creare una stringa letterale che contiene sequenze di escape ma non si desidera che vengano interpretate da Python. Vuoi che siano grezzi . Guarda questi esempi:

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

In tali situazioni puoi semplicemente aggiungere il prefisso letterale al rcarattere in questo modo: r'hello\nworld'e nessuna sequenza di escape verrà interpretata da Python. La stringa verrà stampata esattamente come l'hai creata.

I letterali stringa grezzi non sono completamente "grezzi"?

Molte persone si aspettano che i valori letterali delle stringhe non elaborate siano grezzi, nel senso che "qualsiasi cosa tra le virgolette viene ignorata da Python" . Quello non è vero. Python riconosce ancora tutte le sequenze di escape, semplicemente non le interpreta, ma le lascia invariate. Significa che i valori letterali di stringa grezzi devono ancora essere valori letterali di stringa validi .

Dalla definizione lessicale di una stringa letterale:

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

È chiaro che i valori letterali di stringa (non elaborati) contenenti un carattere di virgolette nuda: 'hello'world'o che terminano con una barra rovesciata: 'hello world\'non sono validi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.