【正規表現】後読み先読みの解説と見分け方


はじめに

個人的な理解のためのアウトプット記事になりますので、説明不足やもっと良い理解の仕方があるかもしれませんが、ご理解いただけますと幸いです。

読者対象

正規表現の後読み先読みがややこしいと感じている方
後読み先読みってそもそも何ぞ?と感じている方

動作環境

本記事の正規表現は以下の環境で動作確認しています。
・Ruby

今回扱う4つの正規表現

  1. 肯定の後読み
    (?<=abc)

  2. 肯定の先読み
    (?=abc)

  3. 否定の後読み
    (?<!abc)

  4. 肯定の先読み
    (?!abc)

※abcは任意の文字列
※abcの部分に\dなど正規表現を入れることも可能ですが、今回は触れません。

この4つの理解が個人的にややこしかったので、記事にしました。

それぞれ何を表すか

上の4つの書き方はすべて「位置」を表します。

肯定の後読み

「肯定の後読み」を例に取りますと、

(?<=abc)は「"abc"という文字列と一致する箇所の直後」を表しています。

ピンときたでしょうか?
わたしも初めは何のことかわかりませんでした。

Rubularという正規表現を試すことができるWEBアプリで試してみます。
https://rubular.com/

以下の例文を使います。

三国志には正史と演技があります
魏、呉、蜀の三国が出てきます
劉備は三国志の登場人物です。

Your regular expression:というところに(?<=三国志)を入れてみます。

すると以下のように
三国志という文字列の直後に水色の縦棒が来ています。

これは「単語の境界」を表します。
アンカー と呼ぶようです。以後アンカーとします。)

これで位置がマッチしました。
指定した単語の直後にアンカーがきていますね。

その他先程ご紹介した3つの正規表現も同じく単語に合わせて位置を表します。

肯定の先読み

(?=abc)で「"abc"という文字列に一致する箇所の直前」を表します。
正規表現は(?<!三国志)を使って試してみます。

Rubularで確認すると、
お察しの通り指定した単語の前にアンカーが来ます。

否定の後読み

(?<!abc)は「"abc"と一致しない文字列の直後」を表します。
例文を少し変えて、3行目の三国志の「志」を「試」に変えてやってみます。

三国志には正史と演技があります
魏、呉、蜀の三国が出てきます
劉備は三国試の登場人物です

正規表現は(?<!三国志)を使って試してみます。

「三国志」の文字と一致しない文字列の直後が複数個マッチしています。

否定の先読み

(?!abc)は「"abc"と一致しない文字列の直前」を表します。
例文は先程同様で、正規表現は(?!三国志)を使って試してみます。

「三国志」の文字と一致しない文字列の直前が複数個マッチしています。

それぞれの読み方の特徴

4つのご紹介した正規表現を以下に並べます
①肯定の後読み (?<=abc)
②肯定の先読み (?=abc)
③否定の後読み (?<!abc)
④否定の先読み (?!abc)

それぞれ似た文ですが、
若干の違いがあります。

肯定か否定かの見分け方

もうお分かりかもしれませんが、以下のように見分けることができます。

肯定なら=を入れる。否定なら!を入れる。
後読みの場合は<を入れる。先読みなら無し。

このような要領で見分けると理解しやすいと思います。

参考

https://qiita.com/jnchito/items/b0839f4f4651c29da408