Warum entsprechen 3 Backslashes 4 in einer Python-Zeichenfolge?

90

Können Sie mir sagen, warum '?\\\?'=='?\\\\?'gibt True? Das macht mich verrückt und ich kann keine vernünftige Antwort finden ...

>>> list('?\\\?')
['?', '\\', '\\', '?']
>>> list('?\\\\?')
['?', '\\', '\\', '?']
kozooh
quelle
8
Letzterer entgeht nichts, so dass er selbst entkommen kann
Padraic Cunningham
1
Keine Notwendigkeit, auch list()nur >>> '?\\\?' '?\\\\?'
einzuschließen
@PadraicCunningham Es wird nicht "selbst entkommen". Was bedeutet das überhaupt?
user253751
Amüsanterweise ist der Grund, dass beide gleich zwei Backslashes sind :-)
RemcoGerlich
@immibis, genau das passiert. Kennen Sie den Unterschied zwischen repr und str? Versuchen Sie, beide mit einem Backslash in der Zeichenfolge zu drucken, und es könnte klar werden
Padraic Cunningham

Antworten:

84

Grundsätzlich, weil Python bei der Backslash-Verarbeitung etwas nachsichtig ist. Zitat aus https://docs.python.org/2.0/ref/strings.html :

Im Gegensatz zu Standard C bleiben alle nicht erkannten Escape-Sequenzen in der Zeichenfolge unverändert, dh der Backslash bleibt in der Zeichenfolge .

(Hervorhebung im Original)

Daher ist es in Python nicht so, dass drei Backslashes gleich vier sind, sondern dass, wenn Sie einem Backslash mit einem Zeichen wie folgen ?, die beiden zusammen als zwei Zeichen durchkommen, da dies \?keine erkannte Escape-Sequenz ist.

Daniel Martin
quelle
6
Das ist das Gegenteil von Nachsicht. Nachsichtig ist das Verhalten aller anderen : "Wenn Sie einen Charakter, der ihn nicht benötigt, mit einem Backslash versehen, führt der Backslash nichts aus." Zusammen mit einer anderen Konvention (dass Backslashing-Alphanumerik sie zu etwas Besonderem macht, Backslashing-Interpunktion sie jedoch immer zu etwas Besonderem macht) erhalten Sie die sehr schöne Eigenschaft, dass Sie eine Zeichenfolge durch Backslashing aller Interpunktion sicher entstellen können, ohne wissen zu müssen, welche Zeichen speziell sind interpeted - eine Eigenschaft, die Python fehlt.
Hobbs
24
Nein, das Gegenteil von milde wäre, einen Fehler auszulösen, wenn Sie ein nicht erkanntes Backslash-Escape verwenden. (Wie fast jede kompilierte Sprache. Denken Sie daran, dass die String-Verarbeitung von Python im Grunde genommen "wie C ist, außer dass wir nicht in die Luft jagen, wenn ungültige Backslash-Escapezeichen übergeben werden".) Außerdem gibt es in einem String unabhängig von der Sprache nur zwei Zeichen, die maskiert werden müssen - Was auch immer Sie als Trennzeichen verwenden, und Backslash selbst. Ich verstehe das Argument nicht, dass es schwierig ist, sich an beide zu erinnern.
Daniel Martin
@ DanielMartin Es gibt einige Sprachen, in denen das Trennzeichen als eigenes Escape-Zeichen fungiert (z 'escape''d'. B. ). Sie müssen sich dort nicht einmal an andere Charaktere erinnern!
SztupY
1
Oh, warte, ich denke, Standard Pascal hat dieses System auch benutzt - siehe nyx.net/~gthompso/self_pasc.txt
Daniel Martin
1
@ DanielMartin SQL auch.
Random832
30

Dies liegt daran, dass Backslash als Escape-Zeichen für die unmittelbar darauf folgenden Zeichen fungiert, wenn die Kombination eine gültige Escape-Sequenz darstellt. Die rund ein Dutzend Escape-Sequenzen sind hier aufgelistet . Dazu gehören die offensichtlichen wie Zeilenumbruch \n, horizontale Registerkarte \t, Wagenrücklauf \rund dunkelere wie benannte Unicode-Zeichen \N{...}, die beispielsweise \N{WAVY DASH}Unicode-Zeichen darstellen \u3030. Der entscheidende Punkt ist jedoch, dass, wenn die Escape-Sequenz nicht bekannt ist, die Zeichenfolge unverändert in der Zeichenfolge verbleibt.

Ein Teil des Problems könnte auch sein, dass die Python-Interpreter-Ausgabe Sie irreführt. Dies liegt daran, dass die Backslashes bei der Anzeige maskiert werden. Wenn Sie diese Zeichenfolgen jedoch drucken , werden die zusätzlichen Backslashes ausgeblendet.

>>> '?\\\?'
'?\\\\?'
>>> 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

Für Ihre spezifischen Beispiele entgeht im ersten Fall '?\\\?'der erste \dem zweiten Backslash und hinterlässt einen einzelnen Backslash, während der dritte Backslash als Backslash verbleibt, da \?es sich nicht um eine gültige Escape-Sequenz handelt. Daher ist die resultierende Zeichenfolge ?\\?.

Im zweiten Fall '?\\\\?'entgeht der erste Backslash dem zweiten und der dritte Backslash dem vierten, was zur Zeichenfolge führt ?\\?.

Deshalb sind drei Backslashes gleich vier:

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

Wenn Sie eine Zeichenfolge mit 3 Backslashes erstellen möchten, können Sie jeden Backslash umgehen:

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

oder Sie finden "rohe" Zeichenfolgen verständlicher:

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

Dadurch wird die Escape-Sequenzverarbeitung für das Zeichenfolgenliteral aktiviert. Weitere Informationen finden Sie unter String-Literale .

mhawke
quelle
Du hast Recht '?\\\?'=='?\\?'gibt False, ich es falsch geschrieben. Das sollte so sein, '?\\\?'=='?\\\\?'wie die Frage zeigt, ich habe es korrigiert.
Kozooh
13

Da \xin einer Zeichenkette, wenn xnicht einer der speziellen backslashable Zeichen wie n, r, t, 0, usw., bewertet in einen String mit einem umgekehrten Schrägstrich und dann ein x.

>>> '\?'
'\\?'
der paul
quelle
7

Auf der Seite zur lexikalischen Python-Analyse unter Zeichenfolgenliteralen unter: https://docs.python.org/2/reference/lexical_analysis.html

Es gibt eine Tabelle, in der alle erkannten Escape-Sequenzen aufgelistet sind.

\\ ist eine Escape-Sequenz, die === \ ist

\? ist keine Escape-Sequenz und ist === \?

also ist '\\\\' '\\' gefolgt von '\\', was '\\' ist (zwei entkommen \)

und '\\\' ist '\\' gefolgt von '\', was auch '\\' ist (einer ist entkommen \ und einer roh \)

Es sollte auch beachtet werden, dass Python im Gegensatz zu einigen anderen Sprachen nicht zwischen einfachen und doppelten Anführungszeichen unterscheidet, die ein String-Literal umgeben.

'String' und "String" sind also in Python genau dasselbe, sie haben keinen Einfluss auf die Interpretation von Escape-Sequenzen.

rkh
quelle
1

Die Antwort von mhawke deckt es ziemlich genau ab. Ich möchte es nur in einer prägnanteren Form und mit minimalen Beispielen, die dieses Verhalten veranschaulichen, wiederholen.

Ich denke, eine Sache, die hinzugefügt werden muss, ist, dass die Escape-Verarbeitung von links nach rechts \nverschoben wird , sodass zuerst der Backslash gefunden wird und dann nach einem Zeichen gesucht wird, das entkommen kann, und dann gefunden nund entkommen wird. \\nfindet den ersten Backslash, findet den zweiten und entkommt ihm, findet nund sieht ihn dann als wörtliches n; \?findet einen Backslash und sucht nach einem Zeichen, dem man entkommen kann, findet einen, ?dem man nicht entkommen kann, und behandelt ihn daher \als wörtlichen Backslash.

Wie mhawke bemerkte, ist der Schlüssel hier, dass der interaktive Interpreter beim Anzeigen einer Zeichenfolge dem Backslash entgeht. Ich vermute, der Grund dafür ist, sicherzustellen, dass Textzeichenfolgen, die vom Interpreter in den Code-Editor kopiert wurden, gültige Python-Zeichenfolgen sind. In diesem Fall führt diese Berücksichtigung der Bequemlichkeit jedoch zu Verwirrung.

>>> 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
\\?
Regnerisch
quelle