Python文字列で3つのバックスラッシュが4に等しいのはなぜですか?


90

なぜ'?\\\?'=='?\\\\?'与えるのTrueか教えてもらえますか?それは私を夢中にさせ、私は合理的な答えを見つけることができません...

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

8
後者は何もエスケープしていないので、それ自体がエスケープされてしまう
Padraic Cunningham

1
含める必要はありませんlist()>>> '?\\\?' '?\\\\?'
daboross

@PadraicCunninghamそれは「それ自体がエスケープされる」ことにはなりません。それは一体何の意味ですか?
user253751 2016

面白いことに、その理由は両方とも2つのバックスラッシュに等しいためです:-)
RemcoGerlich

@immibis、それがまさに起こっていることです。reprとstrの違いを知っていますか?文字列に1つのバックスラッシュを付けて両方を印刷してみてください。それが明らかになる可能性があります
Padraic Cunningham

回答:


84

基本的に、Pythonはバックスラッシュ処理に少し寛容だからです。https://docs.python.org/2.0/ref/strings.htmlからの引用:

標準Cとは異なり、認識されないすべてのエスケープシーケンスは変更されずに文字列に残ります。つまり、バックスラッシュは文字列に残ります

(オリジナルの強調)

したがって、Pythonでは、3つのバックスラッシュが4に等しいということではありません。バックスラッシュの後にのような文字を続けると、認識されたエスケープシーケンスではない?ため、2つが2つの文字として結合\?されます。


6
それは寛大の反対です。Lenientは、「必要のない文字をバックスラッシュした場合、バックスラッシュは何もしない」というほとんどの人行動です。別の規則(バックスラッシュを使用した英数字は特殊文字になる場合がありますが、バックスラッシュを使用すると常に特殊ではなくなります)を使用すると、特別な文字を知らなくても、すべてのパンクチュエーションをバックスラッシュして文字列を安全に分離できる非常に優れたプロパティが得られますinterpeted — Pythonにはないプロパティ。
ホッブズ

24
いいえ、認識できないバックスラッシュエスケープを使用すると、lenientの反対にエラーが発生します。(ほとんどすべてのコンパイル済み言語と同じです。Pythonの文字列処理は基本的に「Cのようですが、無効なバックスラッシュエスケープが渡されても爆破されない」ことを忘れないでください) -区切り文字として使用しているものすべて、およびバックスラッシュ自体。両方を覚えるのは難しいという主張は理解できません。
Daniel Martin

@DanielMartinいくつかの言語では、区切り文字が独自のエスケープ文字(たとえば'escape''d')として機能します。そこで他のキャラクターを覚える必要もありません!
SztupY 2016

1
ああ、標準的なパスカルもそのシステムを使用したと思います-nyx.net/~gthompso/self_pasc.txtを
Daniel Martin

1
@DanielMartin SQLも。
Random832 16

30

これは、組み合わせが有効なエスケープシーケンスを表す場合、バックスラッシュが直後の文字のエスケープ文字として機能するためです。ダースほどのエスケープシーケンスがここにリストされています。それらには、改行\n、水平タブ\t、キャリッジリターンなどの明白なものや、たとえばUnicode文字を表す\r名前付きUnicode文字などのあいまいなものが含まれます。ただし、重要な点は、エスケープシーケンスが不明な場合、文字シーケンスはそのまま文字列に残るということです。\N{...}\N{WAVY DASH}\u3030

問題の一部は、Pythonインタープリターの出力が誤解を招く可能性もあります。これは、表示時に円記号がエスケープされるためです。ただし、これらの文字列を印刷すると、余分なバックスラッシュが消えます。

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

特定の例の場合'?\\\?'、最初のケースでは、最初の\バックスラッシュは1つのバックスラッシュを残して2番目のバックスラッシュをエスケープしますが、3番目のバックスラッシュは\?有効なエスケープシーケンスではないため、バックスラッシュのままです。したがって、結果の文字列は?\\?です。

2番目のケース'?\\\\?'では、最初のバックスラッシュは2番目をエスケープし、3番目のバックスラッシュは4番目をエスケープして、文字列になります?\\?

したがって、3つのバックスラッシュは4つと同じです。

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

3つの円記号を含む文字列を作成する場合は、各円記号をエスケープできます。

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

または、「生の」文字列の方がわかりやすいかもしれません。

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

文字列リテラルのエスケープシーケンス処理が終了します。詳細については、文字列リテラルを参照してください。


あなたは正しいと思い'?\\\?'=='?\\?'ますFalse、私はそれをタイプミスしました。それは'?\\\?'=='?\\\\?'質問が示すように、私はそれを修正しました。
kozooh 2016

13

そのため\x、文字列では、ときxのような特殊なbackslashable文字の一つではないnrt0、など、バックスラッシュと、その後で文字列に評価x

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

7

https://docs.python.org/2/reference/lexical_analysis.htmlの文字列リテラルの下のpython字句解析ページから

認識されたすべてのエスケープシーケンスをリストする表があります。

\\は、=== \であるエスケープシーケンスです。

\?エスケープシーケンスではなく、=== \?

したがって、「\\\\」は「\\」の後に「\\」が続く「\\」(2つのエスケープされた\)

そして '\\\'は '\\'の後に '\'が続き、これも '\\'です(1つはエスケープされ、もう1つは生の\)

また、Pythonは他の一部の言語とは異なり、文字列リテラルを囲む単一引用符と二重引用符を区別しないことに注意してください。

したがって、「文字列」と「文字列」はPythonではまったく同じものであり、エスケープシーケンスの解釈には影響しません。


1

mhawkeの答えはそれをかなりカバーしています、私はもっと簡潔な形で、そしてこの振る舞いを説明する最小限の例でそれを言い直したいだけです。

追加すべきことの1つは、エスケープ処理が左から右に移動するため、\n最初にバックスラッシュを見つけてから、エスケープする文字を探し、次にそれを見つけnてエスケープすることです。\\n最初のバックスラッシュを見つけ、2番目を見つけてエスケープし、次にそれをnリテラルnとして見つけて見ます。\?バックスラッシュを見つけてエスケープする文字を探し、エスケープ?できない文字を見つけ\て、文字どおりのバックスラッシュとして扱います。

mhawkeが指摘したように、ここで重要なのは、対話型インタープリターが文字列を表示するときにバックスラッシュをエスケープすることです。その理由は、インタープリターからコードエディターにコピーされたテキスト文字列が有効なPython文字列であることを確認するためだと思います。ただし、この場合、便宜上のこの手当は混乱を引き起こします。

>>> 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
\\?
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.