web-dev-qa-db-ja.com

Pythonの生の文字列リテラルが単一のバックスラッシュで終わらないのはなぜですか?

技術的には、 ドキュメント で説明されているように、奇数個のバックスラッシュ。

>>> r'\'
  File "<stdin>", line 1
    r'\'
       ^
SyntaxError: EOL while scanning string literal
>>> r'\\'
'\\\\'
>>> r'\\\'
  File "<stdin>", line 1
    r'\\\'
         ^
SyntaxError: EOL while scanning string literal

パーサーは生の文字列のバックスラッシュを通常の文字として扱うことができるようですが(生の文字列とは何ですか?)、私はおそらく明らかな何かを見逃しています。 TIA!

151
cdleary

その理由は、太字で強調したセクションの一部で説明されています。

文字列の引用符はバックスラッシュでエスケープできますしかし、バックスラッシュは文字列に残ります;例えば、 r"\""は、2つの文字で構成される有効な文字列リテラルです。バックスラッシュと二重引用符。 r"\"は有効な文字列リテラルではありません(生の文字列でも奇数のバックスラッシュで終了することはできません)。具体的には、生の文字列を単一のバックスラッシュで終わらせることはできません(バックスラッシュは次の引用文字をエスケープするため)。また、改行が続く単一のバックスラッシュは、行の継続としてではなく、文字列の一部としてこれらの2文字として解釈されることに注意してください。

したがって、生の文字列は100%生ではなく、基本的なバックスラッシュ処理がまだ残っています。

114
oefe

Pythonの生の文字列についての全体的な誤解は、ほとんどの人が他のすべてと同様に(生の文字列内の)バックスラッシュは単なる普通の文字だと考えているということです。そうではない。理解する鍵は、このpythonのチュートリアルシーケンスです。

'r'または '[〜#〜] r [〜#〜]'プレフィックスが存在する場合、バックスラッシュに続く文字が変更されずに文字列に含まれます。すべてのバックスラッシュは文字列に残ります

したがって、バックスラッシュに続く文字is生の文字列の一部。パーサーが生の文字列(ユニコードではない文字列)を入力し、バックスラッシュに遭遇すると、2文字(バックスラッシュとそれに続く文字)があることがわかります。

こちらです:

r'abc\d 'a、b、c、\、dで構成されます

r'abc\'d'で構成されているa、b、c、\、 '、d

r'abc\''で構成されるa、b、c、\、 '

そして:

r'abc\'a、b、c、\、'で構成されますが、終了引用符はありません。

最後のケースは、ドキュメントによると、上記の最後のqouteが文字列ieの一部であるため、パーサーは閉じ引用符を見つけることができないことを示しています。バックスラッシュは文字列を閉じる文字を「むさぼり食う」ので、ここで最後にすることはできません。

80
Artur

そういうものだ!私はそれをPythonの小さな欠陥の1つと考えています!

正当な理由はないと思いますが、それは間違いなく構文解析ではありません。 \を最後の文字として生の文字列を解析するのは本当に簡単です。

問題は、\を生の文字列の最後の文字にすることを許可すると、生の文字列の中に "を入れることができなくなることです。python最後の文字として\を許可します。

ただし、これで問題が発生することはありません。

c:\mypath\などのWindowsフォルダーパスを簡単に記述できないことが心配な場合は、r"C:\mypath"として表すことができます。サブディレクトリ名を追加する必要がある場合は、とにかくそれを行う正しい方法ではないので、文字列の連結でそれをしないでください! os.path.joinを使用します

>>> import os
>>> os.path.join(r"C:\mypath", "subfolder")
'C:\\mypath\\subfolder'
20
hasen

もう1つのトリックは、「\」と評価されるときにchr(92)を使用することです。

私は最近、バックスラッシュの文字列をクリーンアップする必要がありましたが、次のトリックがありました:

CleanString = DirtyString.replace(chr(92),'')

これは「なぜ」の面倒を見ないが、スレッドは差し迫った問題の解決策を探している多くの人々を魅了していることを理解しています。

14
Geekworking

生の文字列をスラッシュで終了させるには、このトリックを使用することをお勧めします。

>>> print r"c:\test"'\\'
test\
10
Charles Beattie

\ "は生の文字列内で許可されているため、文字列リテラルの終わりを識別するために使用することはできません。

最初の「」に遭遇したときに文字列リテラルの解析を停止しないのはなぜですか?

その場合、文字列リテラル内では\ "は許可されません。しかし、許可されます。

8
Brian R. Bondy

r'\'が構文的に正しくない理由は、文字列式が未加工であるにもかかわらず、使用された引用符(シングルまたはダブル)が常にエスケープされる必要があるためです。したがって、単一引用符で囲まれた文字列内で単一引用符を表現する場合、\'を使用する以外の方法はありません。二重引用符についても同様です。

しかし、あなたは使用することができます:

'\\'
3
Gumbo

その後回答を削除した別のユーザー(クレジットを希望するかどうかわからない)は、Python言語デザイナーが同じ解析ルールを使用してパーサーの設計を単純化できる可能性があることを示唆しましたエスケープされた文字を後付けとして未加工の形式に展開します(リテラルが未加工としてマークされている場合)。

面白いアイデアだと思って、後世のためのコミュニティwikiとして取り入れています。

2
cdleary

バックスラッシュは次の引用文字をエスケープするため、生の文字列でも単一のバックスラッシュで終わることはできません。文字列に埋め込むには、周囲の引用文字をエスケープする必要があります。つまり、r "... \"は有効な文字列リテラルではありません。生の文字列は奇数個のバックスラッシュで終わることはできません。
1つのバックスラッシュで生の文字列を終了する必要がある場合は、2つを使用して2つ目を切り捨てることができます。

1
pawandeep singh

いくつかのヒント :

1)パスのバックスラッシュを操作する必要がある場合、標準python module os.pathはあなたの友人です。例えば:

os.path.normpath( 'c:/ folder1 /')

2)バックスラッシュを含む文字列を構築したいが、文字列の最後にバックスラッシュを付けない場合は、生の文字列があなたの友人です(リテラル文字列の前に「r」プレフィックスを使用します)。例えば ​​:

r'\one \two \three'

3)変数Xの文字列の前にバックスラッシュを付ける必要がある場合、これを行うことができます:

X='dummy'
bs=r'\ ' # don't forget the space after backslash or you will get EOL error
X2=bs[0]+X  # X2 now contains \dummy

4)末尾にバックスラッシュを含む文字列を作成する必要がある場合は、ヒント2と3を組み合わせます。

voice_name='upper'
lilypond_display=r'\DisplayLilyMusic \ ' # don't forget the space at the end
lilypond_statement=lilypond_display[:-1]+voice_name

現在lilypond_statementには"\DisplayLilyMusic \upper"が含まれています

長いライブpython!:)

n3on

1
n3on

Cからは、単一の\がエスケープ文字として機能し、改行、タブ、引用符などの特殊文字を文字列に入れることができることは私にはかなり明らかです。

実際、\は最後の文字として許可されません。これは、 "をエスケープし、パーサーをチョークするからです。しかし、先に指摘したように、\は正当です。

1
Robert Ahlskog

この問題に遭遇し、場合によっては部分的な解決策が見つかりました。 python単一のバックスラッシュで文字列を終了することはできませんが、最後に単一のバックスラッシュを持つテキストファイルにシリアル化して保存できます。したがって、必要なのはテキストの保存コンピュータ上で単一のバックスラッシュを使用すると、次のことが可能になります。

x = 'a string\\' 
x
'a string\\' 

# Now save it in a text file and it will appear with a single backslash:

with open("my_file.txt", 'w') as h:
    h.write(x)

ところで、Pythonのjsonライブラリを使用してダンプすると、jsonで動作しません。

最後に、私はSpyderで作業し、変数Explorerで変数の名前をダブルクリックしてスパイダーのテキストエディターで変数を開くと、単一のバックスラッシュが表示され、クリップボードにそのままコピーできることに気付きました(そうではありません)ほとんどのニーズには非常に役立ちますが、一部のニーズには役立つかもしれません。

0
BossaNova