Perché 3 barre rovesciate equivalgono a 4 in una stringa Python?


90

Potresti dirmi perché '?\\\?'=='?\\\\?'True? Questo mi fa impazzire e non riesco a trovare una risposta ragionevole ...

>>> list('?\\\?')
['?', '\\', '\\', '?']
>>> list('?\\\\?')
['?', '\\', '\\', '?']

8
Quest'ultimo non sfugge a nulla, quindi finisce per essere scappato da solo
Padraic Cunningham

1
Non è necessario includere list()nemmeno:>>> '?\\\?' '?\\\\?'
daboross

@PadraicCunningham Non "finisce per essere sfuggito a se stesso". Che cosa vuol dire, anche?
user253751

In modo divertente, il motivo è che sono entrambi uguali a due barre rovesciate :-)
RemcoGerlich

@immibis, questo è esattamente ciò che sta accadendo. Conosci la differenza tra repr e str? Prova a stampare entrambi con una barra rovesciata nella stringa e potrebbe diventare chiaro
Padraic Cunningham

Risposte:


84

Fondamentalmente, perché Python è leggermente indulgente nell'elaborazione del backslash. Citando da https://docs.python.org/2.0/ref/strings.html :

A differenza dello standard C, tutte le sequenze di escape non riconosciute vengono lasciate invariate nella stringa, ovvero la barra rovesciata viene lasciata nella stringa .

(Enfasi nell'originale)

Pertanto, in Python, non è che tre barre rovesciate siano uguali a quattro, è che quando si segue una barra rovesciata con un carattere simile ?, le due insieme vengono visualizzate come due caratteri, perché \?non è una sequenza di escape riconosciuta.


6
È l'opposto di indulgente. Lenient è quasi il comportamento di tutti gli altri di "se si esegue il backslash di un personaggio che non ne ha bisogno, il backslash non fa nulla". Insieme ad un'altra convenzione (che il backslash alfanumerico può renderli speciali, ma la punteggiatura backslash lo rende sempre non speciale), ottieni la proprietà molto carina che puoi tranquillamente eliminare una stringa rovesciando tutta la punteggiatura, senza dover sapere quali caratteri sono speciali interpretato - una proprietà che manca a Python.
hobbs

24
No, l'opposto di indulgente sarebbe generare un errore quando si utilizza un'escape di backslash non riconosciuta. (Come fanno quasi tutti i linguaggi compilati. Ricorda che l'elaborazione delle stringhe di Python è fondamentalmente "come C, tranne per il fatto che non facciamo saltare in aria quando viene consegnato un backslash non valido") Inoltre, in una stringa, qualunque sia la lingua, ci sono solo due caratteri che necessitano di escape - qualunque cosa tu stia utilizzando come delimitatore e barra rovesciata stessa. Non capisco l'argomento secondo cui è difficile ricordare entrambi.
Daniel Martin

@DanielMartin ci sono alcune lingue in cui il delimitatore funziona come il proprio carattere di escape (ad esempio 'escape''d'). Non devi nemmeno ricordare altri personaggi lì!
SztupY

1
Oh aspetta, immagino che anche Pascal standard abbia usato quel sistema - vedi nyx.net/~gthompso/self_pasc.txt
Daniel Martin

1
@DanielMartin SQL anche.
Casuale 832

30

Questo perché la barra rovesciata funge da carattere di escape per i caratteri immediatamente successivi, se la combinazione rappresenta una sequenza di escape valida. Le dozzine di sequenze di escape sono elencate qui . Includono quelli ovvi come la nuova riga \n, la tabulazione orizzontale \t, il ritorno a capo \re quelli più oscuri come i caratteri Unicode denominati utilizzando \N{...}, ad esempio, \N{WAVY DASH}che rappresenta il carattere Unicode \u3030. Il punto chiave però è che se la sequenza di escape non è nota, la sequenza di caratteri viene lasciata nella stringa così com'è.

Parte del problema potrebbe anche essere che l'output dell'interprete Python ti sta fuorviando. Questo perché i backslash vengono sottoposti a escape quando vengono visualizzati. Tuttavia, se stampi quelle stringhe, vedrai scomparire le barre rovesciate extra.

>>> '?\\\?'
'?\\\\?'
>>> print('?\\\?')
?\\?
>>> '?\\\?' == '?\\?'    # I don't know why you think this is True???
False
>>> '?\\\?' == r'?\\?'   # but if you use a raw string for '?\\?'
True
>>> '?\\\\?' == '?\\\?'  # this is the same string... see below
True

Per i tuoi esempi specifici, nel primo caso '?\\\?', il primo \sfugge al secondo backslash lasciando un singolo backslash, ma il terzo backslash rimane come backslash perché \?non è una sequenza di escape valida. Quindi la stringa risultante è ?\\?.

Per il secondo caso '?\\\\?', il primo backslash sfugge al secondo e il terzo backslash sfugge al quarto che risulta nella stringa ?\\?.

Ecco perché tre backslash sono uguali a quattro:

>>> '?\\\?' == '?\\\\?'
True

Se desideri creare una stringa con 3 barre rovesciate, puoi eseguire l'escape di ciascuna barra rovesciata:

>>> '?\\\\\\?'
'?\\\\\\?'
>>> print('?\\\\\\?')
?\\\?

oppure potresti trovare stringhe "grezze" più comprensibili:

>>> r'?\\\?'
'?\\\\\\?'
>>> print(r'?\\\?')
?\\\?

Questo trasforma l'elaborazione della sequenza di escape per la stringa letterale. Vedere String Literals per ulteriori dettagli.


Hai ragione '?\\\?'=='?\\?'False, l'ho digitato male. Dovrebbe essere '?\\\?'=='?\\\\?'come indica la domanda, l'ho corretto.
kozooh

13

Perché \xin una stringa di caratteri, quando xnon è uno dei caratteri speciali backslashable come n, r, t, 0, ecc, restituisce una stringa con una barra rovesciata e poi un x.

>>> '\?'
'\\?'

7

Dalla pagina di analisi lessicale di Python sotto stringhe letterali su: https://docs.python.org/2/reference/lexical_analysis.html

C'è una tabella che elenca tutte le sequenze di escape riconosciute.

\\ è una sequenza di escape che è === \

\? non è una sequenza di escape ed è === \?

quindi "\\\\" è "\\" seguito da "\\" che è "\\" (due \\ con escape)

e "\\\" è "\\" seguito da "\" che è anche "\\" (uno con escape \ e uno grezzo \)

Inoltre, va notato che python non distingue tra virgolette singole e doppie che circondano una stringa letterale, a differenza di altri linguaggi.

Quindi "String" e "String" sono la stessa cosa in Python, non influenzano l'interpretazione delle sequenze di escape.


1

La risposta di mhawke praticamente lo copre, voglio solo riformularlo in una forma più concisa e con esempi minimi che illustrano questo comportamento.

Immagino che una cosa da aggiungere sia che l'elaborazione dell'escape si sposta da sinistra a destra, in modo che \nprima trova il backslash e poi cerca un carattere da scappare, poi lo trova ne lo sfugge; \\ntrova la prima barra rovesciata, trova la seconda ed esegue l'escape, quindi la trova ne la vede come una n letterale; \?trova la barra rovesciata e cerca un carattere di cui eseguire l'escape, trova a ?cui non è possibile eseguire l'escape e quindi tratta \come una barra rovesciata letterale.

Come notato da mhawke, la chiave qui è che l'interprete interattivo sfugge alla barra rovesciata quando mostra una stringa. Immagino che il motivo sia quello di garantire che le stringhe di testo copiate dall'interprete nell'editor di codice siano stringhe Python valide. Tuttavia, in questo caso, questa indennità per comodità crea confusione.

>>> print('\?') # \? is not a valid escape code so backslash is left as-is
\?
>>> print('\\?') # \\ is a valid escape code, resulting in a single backslash
'\?'

>>> '\?' # same as first example except that interactive interpreter escapes the backslash
\\?
>>> '\\?' # same as second example, backslash is again escaped
\\?
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.