Python正規表現における肯定先読み・後読みと否定先読み・後読み
時々、次のようなタイプの問題を解決する必要があります:
文字列 'aaa' を見つけて
'!' に置き換えるが、ただし
'aaa' の後に 'x' が続く場合のみ。'x'
自体は置き換えない。この問題を '力任せに'
解決しようとすると、成功しません:
txt = 'aaax baaa'
res = re.sub('aaax', '!', txt)
print(res) # '! baaa' を出力しますが、期待したのは '!x baaa' です
先読み (Lookahead)
この問題を解決するには、'x' を置き換えるべきではないと示す方法が必要です。
これは、特別な括弧 (?= ) を使って行われます。
この括弧は単に「先を見る」だけで、マッチした内容に「含めません」。
この括弧は 肯定先読み と呼ばれます。
"肯定" というのは、'x' (この場合) が
存在しなければならない (置換が発生する) からです。
この括弧を使って問題を解決してみましょう:
txt = 'aaax baaa'
res = re.sub('aaa(?=x)', '!', txt)
print(res) # '!x baaa' を出力します
また、否定先読み もあります -
(?! ) - これは逆に、何かが存在しては「ならない」ことを示します。
次の例では、'aaa' の後に 'x' が「ない」場合のみ置換が行われます:
txt = 'aaax aaab'
res = re.sub('aaa(?!x)', '!', txt)
print(res) # 'aaax !b' を出力します
後読み (Lookbehind)
同様に、肯定後読み - (?<= ) があります。
次の例では、'aaa' の前に 'x' がある場合のみ置換が行われます:
txt = 'xaaa'
res = re.sub('(?<=x)aaa', '!', txt)
print(res) # 'x!' を出力します
そして、否定後読み もあります -
(?<! )。
次の例では、'aaa' の前に 'x' が「ない」場合のみ置換が行われます:
txt = 'baaa'
res = re.sub('(?<!x)aaa', '!', txt)
print(res) # 'b!' を出力します
実践問題
関数名を含む文字列が与えられます:
txt = 'func1() func2() func3()'
文字列から関数名の配列を取得してください。
タグを含む文字列が与えられます:
txt = '<a href="" class="eee" id="zzz">'
このタグの属性名の配列を取得してください。
変数を含む文字列が与えられます:
txt = '$aaa $bbb $ccc xxxx'
ドル記号 ($) が前に付いている部分文字列を取得してください。