正規表現:AND(かつ)の表現方法

最終更新:2018-07-18 by Joe

正規表現で、論理積「AND」の条件、すなわち「かつ」を表す表現方法についてまとめました。

正規表現の「AND(かつ)」の表現

正規表現において、複数のパターンの論理積「AND」、すなわち「A、かつB」といったパターンの並列表現はややトリッキーです。初学者にはややハードルが高いかもしれませんが、記事後半に解説を加えておきましたので、よくわからない方はご一読下さい。

〇〇を含む、AND(かつ)、〇〇を含む

AND(かつ)条件の例として、リテラル(=ただの文字)のマッチを考えてみます。下記は、「ラーメンを含む、かつ、カレーを含む」という、お子様も大好きなメニューの定番をマッチングする正規表現です。

// ラーメンを含み、かつ、カレーを含む文字列の表現
^(?=.*ラーメン)(?=.*カレー).*$

注目すべきは、「(?=」「)」の括弧です。これは肯定先読みを言いますが、こちらについては、追って解説します。

〇〇を含む、AND(かつ)、〇〇を含むまない

同様に、否定先読みを組み合わせて、このように表現できます。

// ラーメンを含み、かつ、パスタを含まない文字列の表現
^(?=.*ラーメン)(?!.*パスタ).*$

『あ〜、「肯定先読み・否定先読み」ね、おっけ〜」となった方は、これ以上の必要は特に必要ないかと思いますが、この記事では、この「肯定先読み」ついて、少し掘り下げていきます。

【補足】肯定先読みについて

肯定先読みの振る舞いはシンプルとは言い難く、やや理解しにくいところがあります。一方で、「AND(かつ)」の正規表現には必要不可欠な物となっています。

「肯定先読み」とは?

正規表現において「肯定先読み」の表現とは下記のような振る舞いです:

  • 処理位置の前方方向へ向かって文字列の吟味(言明(Assertion)と言います)を行う。
  • マッチングがあれば、そのまま処理位置に戻って処理を再開する。

なんだか、ピンときませんね・・。まずシンプルな例で、肯定先読みの振る舞いを確認しましょう。

「〜で始まる文字列」を考える

下記は「みそ」で始まる文字列の正規表現です。(文字列の範囲を、^と$で囲み「1行」としています。)

// みそで始まる文字列の正規表現
^(?=みそ).*$
// マッチする文字列
みそラーメン
みそスープ?

処理の順番を追っていくと、

  1. 位置指定子の「^」が「文頭」をマッチ。
  2. その後「みそ」の吟味を開始。すなわち、文頭の直後に「みそ」がマッチするかをチェック。
  3. 「みそ」がマッチすれば、文頭の直後に処理位置を戻す。
  4. 「みそ」の直後から、「.*」のマッチングを開始

いかがでしょうか、なんとなくイメージできたでしょうか・・。

「〜を含む」の正規表現

ちなみに、上記の正規表現の例は、そもそも肯定先読みを使わず「^みそ.*$」でも表現出来てしまいます。しかし、次の「みそを含む文字列」例はどうでしょうか?

// みそを含む文字列の正規表現
^(?=.*みそ).*$

// マッチする文字列
みそラーメン
サッポロ一番みそラーメン
手前みそ

これは「^.*みそ.*$」ではマッチできませんね。行頭の「.*」が、先にすべての文字列をマッチしてしまうからです。上記の例では、肯定先読みの特徴である「マッチングのテスト後、処理位置を戻す」振る舞いのおかげで、「みそ」をマッチしたあと、その後の「.*」が、文頭から文章全体をマッチングしてくれます。

これで「みそ」を含む文字列(部分一致)のパターンが表現できました。

改めて、「AND(かつ)」の正規表現

あとは、上記の応用となります。

// みそを含み、かつ、しょうゆ、かつ、しおを含む文字列の正規表現
^(?=.*みそ)(?=.*しょうゆ)(?=.*しお).*$

// マッチする文字列
みそとしょうゆベースのしおラーメン
しょうゆでも、みそでも構わないけど、しおも良い。

先読みのポイントは「処理が戻る」という点です。これにより、パターンを並列に記述でき、〜を含むについて、「AND(かつ)」を表せるようになりました。

正規表現のAND(かつ)に関する参考情報

今回話題に上がった、否定先読み、肯定先読みについて、こちらにも詳しくまとめています。

また、幾分話はシンプルですが、「OR(または)」の正規表現について、こちらにまとめています。