前提としてライブラリre
をインポートしている状態です。
import re
下記の記法は全てテキスト部分のみ抽出をするもので、抽出時の条件がグループ()で示されています。
肯定はグループ内のテキスト条件も一致していた場合に抽出。
否定はグループ内のテキスト条件が一致していなかった場合に抽出。
名称 | 記載方法 | 概要 |
---|---|---|
肯定先読み | テキスト(?=xxx) | xxxが一致したときにテキスト部分を取得 |
否定先読み | テキスト(?!xxx) | xxxが一致しなかったときにテキスト部分を取得 |
肯定後読み | (?<=xxx)テキスト | xxxが一致したときにテキスト部分を取得 |
否定後読み | (?<!xxx)テキスト | xxxが一致しなかったときにテキスト部分を取得 |
肯定先読み
抽出したいテキストに続けて(?=xxx)
を入れることで抽出したいテキストが一致 且つ xxx
部分も一致していた場合にテキスト部分を抽出
re.findall('AB(?=CDEF)', 'ABCDEF') #['AB']
re.findall('AB(?=DEF)', 'ABCDEF') #[]
re.findall('AB(?=CD)', 'ABCDEF') #['AB']
re.findall('.+(?=CD)', 'ABCDEF') #['AB']
re.findall('AB(?=[A-Z]{2,3})', 'ABCDEF') #['AB']
否定先読み
否定先読みでは抽出したいテキストの後ろに(?!xxx)
を記載。
テキスト部分が一致 且つ xxx
部分が一致していない場合にテキスト部分を抽出
re.findall('AB(?!CDEF)', 'ABCDEF') #[]
re.findall('AB(?!DEF)', 'ABCDEF') #['AB']
re.findall('AB(?!CD)', 'ABCDEF') #[]
否定しているので先読みとは逆の結果になります。
肯定後読み
(?<=xxx)
に続けて抽出したいテキストを記載することでxxx
部分が一致 且つ テキストが部分も一致した場合にテキスト部分を抽出
re.findall('(?<=ABCD)EF', 'ABCDEF') #['EF']
re.findall('(?<=BC)EF', 'ABCDEF') #[]
re.findall('(?<=)EF', 'ABCDEF') #['EF']
否定後読み
(?<!xxx)
に続けて抽出したいテキストを記載することでxxx
部分がしていなくて 且つ テキストが部分も一致した場合にテキスト部分を抽出
re.findall('(?<!ABCD)EF', 'ABCDEF') #[]
re.findall('(?<!BC)EF', 'ABCDEF') #['EF']
re.findall('(?<!)EF', 'ABCDEF') #[]
肯定先読みの応用
text = 'Python python PYTHON'
re.findall('py(?=thon)', text) #['py']
re.findall('Py|py(?=thon)', 'Python python PYTHON') #['Py', 'py']
re.findall('py(?=thon)', 'Python python PYTHON', re.IGNORECASE) #['Py', 'py', 'PY']
スクレイピングでありそうな使用方法
text = '住所:東京都新宿区〇〇 〇〇タワー\r地図はこちら'
re.findall('(?<=:).*(?=\r)', text)[0] #東京都新宿区〇〇 〇〇タワー
【参考サイト】
正規表現の先読み・後読みを極める!