正規表現基礎
(?= ) 先読み
カテゴリー:アサーション②
指定文字と1つ前の間で ...
今回から、いよいよ先読みに入ります。
この先読みや、後読みなどは、その分かり難さから大変煙たがられています。
しかし、これらは今まで説明してきたアサーションの仲間です。
アサーションとして、前々回 \b を説明しました。
この \b のマッチ箇所の一つに、\w と \W との間がありました。
\w というように、予め指定パターンが固定されていましたが、先読みの場合これを任意に設定できます。
記述方法は (?= ) として、= の隣に任意のパターンを指定します。
このようにする事で、指定した文字とその前にある文字との間にマッチします。
例えば、(?=円) ならば 円 とその前にある文字の間にマッチが生じます。
対象文字列が5円 5元の場合
このように位置にマッチする、というイメージの延長線上で捉えていくと、理解が容易になってきます。
基本的な動作原理は単純なのです。
また、慣れる事で先読みに関する抵抗感が減らせるので、例をシンプルに、且つ最小構成で挙げて解説します。
難所と言われる先読みを制覇して、意のままに操りましょう。
この記事の難度は、基礎 Cクラスです。
(A: やさしい → E: 難しい)
事前知識として、pythonから正規表現を扱う方法が必要になります。
また、正規表現における文字クラスの知識や、選択を表す正規表現である | OR(または) を理解している事が望ましいです。
(不安な人でも、【Pythonから使う】【基礎1 文字クラス】 【| OR(または)】、で詳しい解説があるので安心です。)
シンプルな例を一個ずつ確認する事で、先読みに慣れていきましょう。
難度 : | |
事前知識: | Pythonの基礎文法(reモジュールを含む)。正規表現の文字クラスや選択等。 |
学習効果: | 先読みの性質である、任意に設定したパターンの前にマッチする、という事を理解出来る。 |
Contens | 目次
Chapter1 | Pythonで実行 |
Chapter1 Pythonで実行
(?=a)
最初の例として、文字列パターンが (?=a) の場合を考えます。
これは、a とその前にある文字の間にマッチします。
対象文字列が map なら a とその前にある m の間です。
re_meta20_1.py import re pattern = re.compile("(?=a)") st = "map" print("↓ 対象文字列\n"+st) result_iter = pattern.finditer(st) for result in result_iter: print("match:",result.group()) print("位置",result.span())
実行結果
予想通り、m と a の間にマッチしました。
a を先頭や末尾にも並べて、 aaa のようにして実行してみます。
各々 a の前にヒットするはずです。
re_meta20_2.py import re pattern = re.compile("(?=a)") st = "aaa" print("↓ 対象文字列\n"+st) result_iter = pattern.finditer(st) for result in result_iter: print("match:",result.group()) print("位置",result.span())
実行結果
これも想定通りの結果です。
次に空白を挟んで、a a を対象文字列とします。
re_meta20_3.py import re # a と a の間は半角スペース pattern = re.compile("(?=a)") st = "a a" print("↓ 対象文字列\n"+st) result_iter = pattern.finditer(st) for result in result_iter: print("match:",result.group()) print("位置",result.span())
実行結果
スペースが存在しても、a の前にマッチするという性質は変わりません。
もう一つ例を挙げます。
文字列パターンが (?=s) であり、対象文字列を seasons とする場合です。
re_meta20_4.py import re pattern = re.compile("(?=s)") st = "seasons" print("↓ 対象文字列\n"+st) result_iter = pattern.finditer(st) for result in result_iter: print("match:",result.group()) print("位置",result.span())
実行結果
それぞれ s の前にマッチしています。
今度は、(?=s) だけでなく単語と組み合わせて使ってみます。
a(?=s)
対象文字列は、meta20_4.py と同様に seasons とします。
但し、文字列パターンを a(?=s) とする事で、s の前にある a という文字にマッチします。
re_meta20_5.py import re pattern = re.compile("a(?=s)") st = "seasons" print("↓ 対象文字列\n"+st) result_iter = pattern.finditer(st) for result in result_iter: print("match:",result.group()) print("位置",result.span())
実行結果
狙い通り、a という文字に一致しました。
次の例では、通貨表示が 円 である数字を取得します。
re_meta20_6.py import re pattern = re.compile("\d(?=円)") st = "5円 3元 9ドル 1円 8貫文 €7" print("↓ 対象文字列\n"+st) result_iter = pattern.finditer(st) for result in result_iter: print("match:",result.group()) print("位置",result.span())
実行結果
5円を取得出来ました。
メタキャラクタと組み合わせて、円の他にドルの値もその対象にします。
(?= | )
選択(OR)を表す正規表現は | です。
(| については【| OR(または)】で詳しく説明しています。)
\d(?=円|ドル) のようにすると、円の他にドルの前にある数字にマッチします。
re_meta20_7.py import re pattern = re.compile("\d(?=円|ドル)") st = "5円 3元 9ドル 8貫文 €7" print("↓ 対象文字列\n"+st) result_iter = pattern.finditer(st) for result in result_iter: print("match:",result.group()) print("位置",result.span())
実行結果
5円の他に9ドルを得られました。
この他にも、$ を使ってみます。
$ は、文字列の末尾を意味します。
($ については【$ 文字列の末尾】で詳しく説明しています。)
文末の日付を抽出するには、以下のようにします。
re_meta20_8.py import re pattern = re.compile("\d(?=日$)") st = "令和2年3月4日 平成4年8月9日" print("↓ 対象文字列\n"+st) result_iter = pattern.finditer(st) for result in result_iter: print("match:",result.group()) print("位置",result.span())
実行結果
4日ではなく、9日を対象にできました。
続けて例を出します。
. の前にある数字を狙います。
. はそのまま使うと任意の1文字になってしまうので、\ (バックスラッシュ)と併用します。
(\ については【\ エスケープ文字の働き】で詳しく説明しています。)
re_meta20_9.py import re pattern = re.compile("\d(?=\.)") st = "7.7 2.45 a.m" print("↓ 対象文字列\n"+st) result_iter = pattern.finditer(st) for result in result_iter: print("match:",result.group()) print("位置",result.span())
実行結果
問題無く取得出来ました。
先読みの説明はここで終了です。
多くの例をみてきたので、先読みの性質である、任意に設定したパターンの前にマッチする、という事を理解出来ました。
これにより、取得したい部分が、ある文字列の前にある場合に役立つでしょう。
次回は、先読みとは反対の位置にマッチする後読みです。
関連記事
\b 単語の境界
正規表現: | アサーション② |
難度 : | 基礎 |
事前知識: | Python基礎(reモジュール)。文字クラス等。 |
学習効果: | 単語の境界とされる位置を的確に認識できるようになる。 |
\B 単語の境界でない
正規表現: | アサーション② |
難度 : | 基礎 |
事前知識: | Python基礎(reモジュール)。文字クラス等。 |
学習効果: | 単語の境界でない位置を的確に認識できるようになる。 |
(?= ) 先読み
正規表現: | アサーション② |
難度 : | 基礎 |
事前知識: | Python基礎(reモジュール)。文字クラスや選択等。 |
学習効果: | 先読みの性質である、任意に設定したパターンの前にマッチする、という事を理解出来る。 |
(?<= ) 後読み
正規表現: | アサーション② |
難度 : | 基礎 |
事前知識: | Python基礎(reモジュール)。文字クラスや選択等。 |
学習効果: | 後読みの性質である、任意に設定したパターンの後にマッチする、という事を理解出来る。 |
(?! ) 否定先読み
正規表現: | アサーション② |
難度 : | 基礎 |
事前知識: | Python基礎(reモジュール)。文字クラスや選択等。 |
学習効果: | 否定先読みの性質である、任意に設定したパターン以外の前でマッチする、という事を理解出来る。 |
(?<! ) 否定後読み
正規表現: | アサーション② |
難度 : | 基礎 |
事前知識: | Python基礎(reモジュール)。文字クラスや選択等。 |
学習効果: | 否定後読みの性質である、任意に設定したパターン以外の後でマッチする、という事を理解出来る。 |
正規表現をPythonから使うには ?
正規表現: | Pythonから使う |
難度 : | 入門 |
事前知識: | Pythonの基礎文法 |
学習効果: | pythonから正規表現を使う一連の流れを掴む |
ハロー ! メタキャラクタ
正規表現: | メタキャラクタの概要 |
難度 : | 入門 |
事前知識: | 不要 |
学習効果: | メタキャラクタの概要を掴む |
正規表現とは?
正規表現: | 概要 |
難度 : | 入門 |
事前知識: | 不要 |
学習効果: | 正規表現の概要を知る |
PR