エスケープの問題
正規表現ではいくつかの文字がパターンとしての特別の意味を持つが、その文字そのものをマッチングの対象としたいときにはバックスラッシュ(\)でエスケープする。
1 2 3 4 5 6 |
import re s = "Does it work?" print(re.search("\?", s)) # <_sre.SRE_Match object; span=(12, 13), match='?'> |
さらに検索対象の文字列にバックスラッシュが含まれている場合には、バックスラッシュ自身をエスケープしなければならない(\\)。このようなケースは、ファイルパスの区切りにバックスラッシュが使われている場合やLATexの\begin~\endなど多くある。
下の例は”\bigin”という文字列を検索する場合。
1 2 3 4 5 6 7 8 9 10 11 12 |
import re s = "\\begin" print(s) print(re.search("\begin", s)) print(re.search("\\begin", s)) print(re.search("\\\\begin", s)) # \begin # None # None # <_sre.SRE_Match object; span=(0, 6), match='\\begin'> |
- 検索される側の文字列のバックスラッシュをエスケープしなければならない(3行目)
- その文字列をprintしてみると意図した内容になっている(4行目と9行目)
- 次にパターン文字の方で、”\begin”とそのまま試してみるとヒットしない(5行目と10行目)
- これは最初の”\b”がPythonのエスケープシーケンス(バックスペース)として解釈されたため
- そこでバックスラッシュをエスケープしてもヒットしない(6行目と11行目)
- Pythonでは文字としてのバックスラッシュとして解釈されるが、今度は正規表現として解釈したとき単独の特殊文字としての’\’となるため
- 2つのバックスラッシュそれぞれをエスケープするようにしてやっとヒットさせることができる(7行目と11行目)
raw文字列
Pythonでは、バックスラッシュを単なる文字として解釈するためのraw文字列が組み込まれていて、文字列リテラルの前に’r’か’R’を付けるだけでよい。”””で囲まれた複数行文字列でも同じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
print("Hello\nPython") # Hello # Python print(r"Hello\nPython") # Hello\nPython print("""abcd\nefgh ijkl\nmnop""") # abcd # efgh # ijkl # mnop print(r"""abcd\nefgh ijkl\nmnop""") # abcd\nefgh # ijkl\nmnop |
また、Python3で文字列変数の文字列をraw文字列に変換するには、repr()
関数を使う。ただしその結果はシングルクォートで囲まれているため、それを取り除かなくてはいけない。
1 2 3 4 5 6 7 8 9 10 |
s = "Hello\nPython" print(s) # Hello # Python print(repr(s)) # 'Hello\nPython' print(repr(s)[1:-2]) # Hello\nPytho |
また複数行文字列の場合は、リテラルでのr指定と変数へのrepr()
適用で結果が異なってくる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
s = """abc\ndef ghi\njkl""" print(s) # abc # def # ghi # jkl print(repr(s)) # 'abc\ndef\nghi\njkl' s = r"""ABC\nDEF GHI\nJKL""" print(s) # ABC\nDEF # GHI\nJKL print(repr(s)) # 'ABC\\nDEF\nGHI\\nJKL' |