正規表現

正規表現の先読みと後読み – 肯定と否定 | 後ろから最初にマッチなど覚え方も解説

正規表現の先読みと後読みを解説
記事の要約
ことば書き方覚え方
肯定先読み(?=XX)( )を読んで◯なら、( )の先(前)にマッチする
否定先読み(?!XX)( )を読んで×なら、( )の先(前)にマッチする
肯定後読み(?<=XX)( )を読んで◯なら、( )の後(うしろ)にマッチする
否定後読み(?<!XX)( )を読んで×なら、( )の後(うしろ)にマッチする

肯定先読みや否定先読み、肯定後読み、否定後読みは正規表現においてマッチするかの判定はしつつも、マッチやキャプチャそのもの対象からは外す表し方です。マッチするパターンを限定したいが、検索の文字列には含めたくないときに便利です。

肯定先読みは「?=」

肯定先読みとは、特定のパターンにマッチした場合にその先(前)にアンカーを設置する書き方で「?=」のように記載します。言葉で説明するより見たほうが早いので例で紹介しましょう。

// 〇〇シティとなる言葉を探したい
.*(?=シティ)

// 検索対象
マサラタウン // NG
トキワシティ // OK「トキワ」
ニビシティ   // OK「ニビ」
ハナダシティ // OK「ハナダ」

何らかの言葉+シティとなる言葉を探しつつ、ヒットする際にはシティの言葉が入らないようにしています。これを肯定先読みを使わずに普通にかくと「〇〇シティ」がそのままマッチします。

// 〇〇シティとなる言葉を探したい
.*シティ

// 検索対象
マサラタウン // NG
トキワシティ // OK「トキワシティ」
ニビシティ   // OK「ニビシティ」
ハナダシティ // OK「ハナダシティ」

「〇〇シティ」の「〇〇」部分のみマッチさせたいが、条件としては「シティ」が後ろにつくことを表現したい場合に肯定先読みが使えます。

アンカーとは特定の位置にマッチさせる表現

正規表現のアンカーとは文字ではなく位置にマッチさせる正規表現の書き方です。たとえば「^」は正規表現の行頭に、「$」は正規表現の行末にマッチします。これらは直接表現自体をキャプチャするわけではないものの、抽出の対象を限定できる点が便利です。

// (行頭)123XX(行末)となる数値にマッチ
^123\d*$

// 検索対象
01234  // NG
12340  // OK (行頭)の後に123が続くため
23401  // NG

上記の例だと「^」や「$」自体はヒットする文字列には含まれません。ただ行頭の次に123が来ることを示すアンカーの役割を果たしています。

否定先読みは「?!」

否定先読みとは特定のパターンにマッチした場合にその先(前)にアンカーを設置する書き方で「?!」のように記載します。肯定先読みの否定のパターンとなります。

// 〇〇〇タウンとならない言葉を探したい
^...(?!タウン)

// 検索対象
マサラタウン // NG
トキワシティ // OK「トキワ」
ハナダシティ // OK「ハナダ」

3文字+タウンが後ろに続かないパターンを探します。こちらも「〇〇シティ」がマッチした際の言葉に含まれないように調整ができています。

肯定後読みは「?<=」

肯定後読みとは、特定のパターンにマッチした場合にその後(後ろ)にアンカーを設置する書き方で「?<=」のように記載します。肯定先読みと異なり(?<=XXXX)の後の部分にアンカーが来るように表せるため、表現の前半に登場する機会が多いです。

// 「野生の」と「が」で挟まれているポケモンのみを抽出したい
(?<=野生の).+(?=が)

// 抽出対象
あ!野生のピカチュウがあらわれた!  // 「ピカチュウ」
つりあげたコイキングがとびかかってきた!  // ×
シゲルはラッタをくりだした!  // ×
あ!野生のオニスズメがとびだしてきた!  // 「オニスズメ」

否定後読みは「?<!」

肯定後読みとは、特定のパターンにマッチした場合にその後(後ろ)にアンカーを設置する書き方で「?<!」のように記載します。否定先読みと異なり(?<!XXXX)の後の部分にアンカーが来るように表せる点は、肯定後読みと同じです。

// ピカチュウ以外の場合でLv.を抽出したい
(?<!ピカチュウ)Lv\.\d{1,3}

// 抽出対象
ピカチュウLv.12  // ×
ヒトカゲLv.16  // 「Lv.16」
フシギダネLv.12  // 「Lv.12」
ゼニガメLv.14  // 「Lv.14」

先読みと後読みの覚え方

オーキド博士

先読みと書いてあるのに後ろに設置したり、後読みと書いてあるのに続く言葉の先を指定したりと紛らわしいのう…

シャワーズ

肯定先読みは「( )を読んで◯なら、( )の先(前)にアンカーを置く」とおぼえましょう!

肯定先読みや否定先読み、肯定後読み、否定後読みの覚え方をまとめると次のとおりです。

ことば書き方覚え方
肯定先読み(?=XXXX)( )を読んで◯なら、( )の先(前)にマッチする
否定先読み(?!XXXX)( )を読んで×なら、( )の先(前)にマッチする
肯定後読み(?<=XXXX)( )を読んで◯なら、( )の後(うしろ)にマッチする
否定後読み(?<!XXXX)( )を読んで×なら、( )の後(うしろ)にマッチする

これも言葉だけではややこしいので例を見ながら考えてましょう。

例:肯定先読み&肯定後読みでタグの中身とマッチ

肯定先読みと肯定後読みを組み合わせるとHTMLタグの中身とマッチできます。下の例では「<h1>」と「</h1>」の間に挟まれているタグを探しています。

// <h1>タグで囲まれている中身にマッチしたい
(?<=<h1>).*(?=<\/h1>)

// 抽出対象
<h1>サトシの手持ち</h1> // 「サトシの手持ち」
<h2>ピカチュウ</h2> // ×

「(?<=)」は肯定後読みで「( )を読んで◯なら、( )の後(うしろ)にマッチする」なため、「<h1>」を読んで◯なら「<h1>」の後ろの位置にマッチします。

「(?=)」は肯定先読みで「( )を読んで◯なら、( )の先(前)にマッチする」なため、「</h1>」を読んで◯なら「</h1>」の前の位置にマッチします。

この2つの条件を組み合わせると「<h1>」の後にマッチ、「</h1>」の前にマッチの2条件を満たした文言を抽出という表現ができるわけです。