先読みと後読みを使ったパターンの記述

正規表現における先読みと後読みは、マッチするかどうか確認は行うけれどマッチした文字列としては取得しないときに利用します。先読みには肯定先読みと否定先読み、後読みには肯定先読みと否定先読み、がそれぞれ用意されています。ここでは Java を使って正規表現で先読みと後読みを使用する方法について解説します。

(Last modified: )

正規表現における先読みと後読みとは

先読み(肯定先読み、否定先読み)と後読み(肯定後読み、否定後読み)の書式は次の通りです。

パターンA(?=パターンB)     肯定先読み
パターンA(?!パターンB)     否定先読み
(?<=パターンB)パターンA    肯定後読み
(?<!パターンB)パターンA    否定後読み

先読みの場合はパターン A の直後にパターン B が続く場合(または続かない場合)にマッチし、後読みの場合は パターン A の直前にパターン B がある場合(またはない場合)にマッチします。どちらもパターン B も含めてマッチするかどうか判断しますが、マッチした文字列として取得するのはパターン A にマッチした部分だけです。

それでは順に見ていきます。

※ 先読みと後読みが実際にどのように対象の文字列にマッチするのかについて、より詳しくは「正規表現における先読みと後読みを使ったパターン」を参照されてください。

肯定の先読み

肯定の先読みは、対象の文字列がパターン A の直後にパターン B に続く場合にマッチします。この時、マッチした値としてはパターン A にマッチした部分だけを取得します。

パターンA(?=パターンB)     肯定先読み

例えば次のパターンで考えてみます。

String regex = "smart(?=phone)";

smart のあとに phone が続く場合のみマッチします。 smartphone はマッチしますが、 smart や smartwatch はマッチしません。そしてマッチした文字列として取得するのは smart のみです。

サンプルコード

それでは簡単なサンプルプログラムを作って試してみます。テキストエディタで次のように記述したあと、 JSample15-1.java という名前で保存します。

import java.util.regex.*;

class JSample15_1{
  public static void main(String[] args){
    String regex = "smart(?=phone)";
    Pattern p = Pattern.compile(regex);

    String[] target = {"smart", "smartphone", "smartwatch"};

    for (int i = 0; i < target.length ; i++){
      Matcher m = p.matcher(target[i]);
      System.out.print(target[i] + "は");
      if (m.find()){
        System.out.println("マッチしました");
        System.out.println("マッチしたのは " + m.group() + " です");
      }else{
        System.out.println("マッチしませんでした");
      }
    }
  }
}

コンパイルを行います。

javac -encoding UTF-8 JSample15_1.java

その後で、次のように実行してください。

java JSample15_1

肯定の先読み(1)

肯定の先読みを使って smart のあとに phone が続く場合のみマッチするようにしました。

否定の先読み

否定の先読みは、対象の文字列がパターン A の直後にパターン B が続かない場合にマッチします。この時、マッチした値としてはパターン A にマッチした部分だけを取得します。

パターンA(?!パターンB)     否定先読み

例えば次のパターンで考えてみます。

String regex = "smart(?!phone)";

smart のあとに phone が続かない場合のみマッチします。 smartphone にはマッチしませんが、 smart や smartwatch はマッチします。そしてマッチした文字列として取得するのは smart のみです。

サンプルコード

それでは簡単なサンプルプログラムを作って試してみます。テキストエディタで次のように記述したあと、 JSample15-2.java という名前で保存します。

import java.util.regex.*;

class JSample15_2{
  public static void main(String[] args){
    String regex = "smart(?!phone)";
    Pattern p = Pattern.compile(regex);

    String[] target = {"smart", "smartphone", "smartwatch"};

    for (int i = 0; i < target.length ; i++){
      Matcher m = p.matcher(target[i]);
      System.out.print(target[i] + "は");
      if (m.find()){
        System.out.println("マッチしました");
        System.out.println("マッチしたのは " + m.group() + " です");
      }else{
        System.out.println("マッチしませんでした");
      }
    }
  }
}

コンパイルを行います。

javac -encoding UTF-8 JSample15_2.java

その後で、次のように実行してください。

java JSample15_2

否定の先読み(1)

否定の先読みを使って smart のあとに phone が続かない場合のみマッチするようにしました。

肯定の後読み

肯定の後読みは、対象の文字列がパターン A の前にパターン B がある場合にマッチします。この時、マッチした値としてはパターン A にマッチした部分だけを取得します。

(?<=パターンB)パターンA    肯定後読み

例えば次のパターンで考えてみます。

String regex = "(?<=digital)camera";

camera の直前に digital がある場合のみマッチします。 digitalcamera はマッチしますが、 camera や analogcamera はマッチしません。そしてマッチした文字列として取得するのは camera のみです。

サンプルコード

それでは簡単なサンプルプログラムを作って試してみます。テキストエディタで次のように記述したあと、 JSample15-3.java という名前で保存します。

import java.util.regex.*;

class JSample15_3{
  public static void main(String[] args){
    String regex = "(?<=digital)camera";
    Pattern p = Pattern.compile(regex);

    String[] target = {"camera", "digitalcamera", "analogcamera"};

    for (int i = 0; i < target.length ; i++){
      Matcher m = p.matcher(target[i]);
      System.out.print(target[i] + "は");
      if (m.find()){
        System.out.println("マッチしました");
        System.out.println("マッチしたのは " + m.group() + " です");
      }else{
        System.out.println("マッチしませんでした");
      }
    }
  }
}

コンパイルを行います。

javac -encoding UTF-8 JSample15_3.java

その後で、次のように実行してください。

java JSample15_3

肯定の後読み(1)

肯定の後読みを使って camera の前に digital がある場合のみマッチするようにしました。

否定の後読み

否定の後読みは、対象の文字列がパターン A の前にパターン B がない場合にマッチします。この時、マッチした値としてはパターン A にマッチした部分だけを取得します。

(?<!パターンB)パターンA    否定後読み

例えば次のパターンで考えてみます。

String regex = "(?<!digital)camera";

camera の直前に digital がない場合のみマッチします。 digitalcamera にはマッチしませんが、 camera や analogcamera はマッチします。そしてマッチした文字列として取得するのは camera のみです。

サンプルコード

それでは簡単なサンプルプログラムを作って試してみます。テキストエディタで次のように記述したあと、 JSample15-4.java という名前で保存します。

import java.util.regex.*;

class JSample15_4{
  public static void main(String[] args){
    String regex = "(?<!digital)camera";
    Pattern p = Pattern.compile(regex);

    String[] target = {"camera", "digitalcamera", "analogcamera"};

    for (int i = 0; i < target.length ; i++){
      Matcher m = p.matcher(target[i]);
      System.out.print(target[i] + "は");
      if (m.find()){
        System.out.println("マッチしました");
        System.out.println("マッチしたのは " + m.group() + " です");
      }else{
        System.out.println("マッチしませんでした");
      }
    }
  }
}

コンパイルを行います。

javac -encoding UTF-8 JSample15_4.java

その後で、次のように実行してください。

java JSample15_4

否定の後読み(1)

否定の後読みを使って camera の前に digital がない場合のみマッチするようにしました。

-- --

Java を使って正規表現で先読みと後読みを使用する方法について解説しました。

( Written by Tatsuo Ikura )

プロフィール画像

著者 / TATSUO IKURA

これから IT 関連の知識を学ばれる方を対象に、色々な言語でのプログラミング方法や関連する技術、開発環境構築などに関する解説サイトを運営しています。