Python: 正規表現で複数行マッチングの置換を行う
Pythonの正規表現で複数行マッチングの置換を行う
Pythonのre
モジュールを使って複数行に渡る正規表現マッチング・置換を行う場合はflags
オプションに適宜re.MULTILINE
やre.DOTALL
を指定する。
# 直接置換する場合 re.sub(pattern, repl, string, flags=(re.MULTILINE | re.DOTALL)) # compileする場合 r = re.compile(pattern, flags=(re.MULTILINE | re.DOTALL)) re.sub(pattern, repl, string)
具体的な内容
^
や$
を各行にマッチさせるre.MULTILINE
フラグ指定
re.MULTILINE
を指定しない場合、^
は文字列の先頭に、$
は文字列の末尾しかマッチしない。つまり1つの文字列変数につきそれぞれ1箇所しかマッチし得ない。なので改行を含む文字列で各行の 先頭や末尾(改行)にマッチさせたい場合はre.MULTILINE
を指定する必要がある
例えば、以下の文字列(SQL)のコメント行を2行とも削除したい場合
# この文字列のコメント部分を削除したい query = """\ -- this is 1st comment -- this is 2nd comment select * from table limit 10; """
re.MULITILINE
フラグ指定がないと1行しか削除されません
# re.MULITILINE指定なしで削除 re.sub(r'^---*.*', '', query) #>-- this is 2nd comment #>select * from table limit 10;
re.MULITILINE
フラグ指定を行うと2行とも削除されます
# re.MULITILINE指定して削除 re.sub(r'^\s*---*.*$', '', query, flags=re.MULTILINE) #>select * from table limit 10;
ちなみにre.MULITILINE
フラグ指定なしで正規表現$
をパターンに入れると何も削除されません。マッチないからです。フラグ指定なしでは$
は文字列の末尾にしかマッチしません。行の末尾にはマッチしません。
# re.MULITILINE指定なしで、$を入れる re.sub(r'^---*.*$', '', query) #>-- this is 1st comment #>-- this is 2nd comment #>select * from table limit 10;
re.MULTILINE(原文) 指定されると、パターン文字 '^' は、文字列の先頭および各行の先頭(各改行の直後)とマッチします;そしてパターン文字 '$' は文字列の末尾および各行の末尾 (改行の直前) とマッチします。デフォルトでは、 '^' は、文字列の先頭とだけマッチし、 '$' は、文字列の末尾および文字列の末尾の改行の直前(がもしあれば)とマッチします。6.2. re — 正規表現操作
.
を改行(\n)にもマッチさせるre.DOTALL
フラグ指定
re.DOTALL
フラグ指定が無いと.
は改行にはマッチしません。re.DOTALL
フラグ指定をすることで改行にもマッチします。
同様に以下の文字列(SQL)の/* ~ */コメント行のすべてを削除したい場合
query = """\ /* this is 1st comment this is 2nd comment */ select * from table limit 10; """
フラグ指定がないと削除されません
# re.MULITILINE指定なし re.sub(r'/\*.*\*/', '', query) #>/* #>this is 1st comment #>this is 2nd comment #>*/ #>select * from table limit 10;
re.DOTALL
フラグ指定を行うと4行とも削除されます
# re.MULITILINE指定 re.sub(r'/\*.*\*/', '', query, flags=re.DOTALL) #>select * from table limit 10;
※ちなみにこれでコメント削除されるんですが、実際に上記のパターンをこのまま使うと、/*~*/が2箇所以上出てきた場合、コメントブロックに挟まれた途中のコードも全部消えるので注意が必要です(greedy matching; どう書くのが良いんでしょう。教えてください)
re.DOTALL¶(原文) 特殊文字 '.' を、改行を含む任意の文字と、とにかくマッチさせます;このフラグがなければ、 '.' は、改行 以外の 任意の文字とマッチします。6.2. re — 正規表現操作
フラグを両方指定する場合
フラグなのでORを取れば大丈夫です。
flags = (re.MULITILINE | re.DOTALL)