リージョン(対象文字列の中のパターンと比較する範囲)を設定する

広告

正規表現ではパターンが指定した対象文字列とマッチするかどうかを調べますが、文字列の先頭から末尾までではなく対象文字列の指定した範囲にある文字列だけを対象にパターンとマッチするか調べることができます。ここでは Java の正規表現でリージョン(対象文字列の中のパターンと比較する範囲)を設定する方法について解説します。

リージョンを設定する

対象文字列の中で、パターンと比較する範囲を設定するには Matcher クラスの region メソッドを使用します。書式は次のとおりです。

public Matcher region​(int start, int end)

パラメータ:
start - 検索を開始する位置のインデックス(その値も含む)
end - 検索を終了する位置のインデックス(その値を含まない)

戻り値:
この正規表現エンジン

例外:
IndexOutOfBoundsException - startまたはendがゼロより小さい場合、startが入力シーケンスの長さより大きい場合、endが入力シーケンスの長さより大きい場合、またはstartがendより大きい場合。

1 番目の引数にパターンとマッチするかどうか検索する先頭の文字のインデックスを指定します。 2 番目の引数に検索する最後の文字の次の文字のインデックスを指定します。

次のサンプルをみてください。

// java.util.regex.*のインポートが必要です
import java.util.regex.*;

String regex  = ".er\b";
Pattern p = Pattern.compile(regex);

Matcher m = p.matcher​("dancer singer");

今回は任意の 1 文字のあとに er という文字列が続き、そのあとで単語境界が続く文字列とマッチするパターンです。リージョンを設定していない場合には cer の部分とマッチします。

dancer singer

それでは対象の文字列にリージョンを設定してみます。

// java.util.regex.*のインポートが必要です
import java.util.regex.*;

String regex  = ".er\b";
Pattern p = Pattern.compile(regex);

Matcher m = p.matcher​("dancer singer");
m.region(7, 13);

Matcher オブジェクトを作成したあと、 Matcher オブジェクトに対してリージョンを設定します。今回は対象の文字列の中で 7 番目のインデックスの文字から 13 番目のインデックスの前の文字までが対象となります。

リージョンを設定する(1)

対象の文字列の中で指定した範囲の文字列が対象となるため、今回は ger の部分とマッチします。

dancer singer

このようにリージョンを設定することで、対象の文字列全体ではなく対象の文字列の指定した範囲の文字列を対象としてパターンとマッチするかどうか調べることができます。

サンプルコード

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

import java.util.regex.*;

class JSample26_1{
  public static void main(String[] args){
    String target = "dancer singer";

    String regex = "\\b.*?er";
    Pattern p = Pattern.compile(regex);

    Matcher m1 = p.matcher​(target);
    if (m1.find()){
      System.out.println(m1.group());
    }else{
       System.out.println("not match");     
    }

    Matcher m2 = p.matcher​(target);
    m2.region(7, 13);
    if (m2.find()){
      System.out.println(m2.group());
    }else{
       System.out.println("not match");     
    }
  }
}

コンパイルを行います。

javac -encoding UTF-8 JSample26_1.java

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

java JSample26_1

リージョンを設定する(2)

リージョンを設定することで、対象の文字列全体ではなく指定した範囲の文字列を対象にマッチするかどうか調べることができました。

設定されているリージョンの開始インデックスと終了インデックスを取得する

Matcher オブジェクトに対してリージョンを設定した場合、現在設定されているリージョンの開始インデックスと終了インデックスをそれぞれ取得することができます。

開始インデックスを取得するいは Matcher クラスの regionStart メソッドを使用します。

public int regionStart()

戻り値:
この正規検索エンジンの領域の始点

終了インデックスを取得するいは Matcher クラスの regionEnd メソッドを使用します。

public int regionEnd()

戻り値:
この正規表現エンジンの領域の終点

それぞれのメソッドを実行すると、現在設定されているリージョンの開始インデックスと終了インデックスをそれぞれ戻り値として返します。

次のサンプルをみてください。

Matcher m = p.matcher​("dancer singer");
m.region(7, 13);

System.out.println(m.regionStart());  // 7
System.out.println(m.regionEnd());    // 13

設定されているリージョンの開始インデックスと終了インデックスをそれぞれ取得しました。

アンカー境界の設定を行う

メタ文字のキャレット(^)やドル記号($)はそれぞれ文字列全体の先頭および末尾にマッチします。次の例を見てください。

// java.util.regex.*のインポートが必要です
import java.util.regex.*;

String regex  = "^sea";
Pattern p = Pattern.compile(regex);

Matcher m = p.matcher​("seaduck and seahorse");

パターン ^sea は文字列の先頭から始まり、 sea と続く文字列とマッチします。よって seaduck の sea にはマッチしますが seahorse の sea にはマッチしません。

seaduck and seahorse

ここで対象の文字列にリージョンを設定してみます。

// java.util.regex.*のインポートが必要です
import java.util.regex.*;

String regex  = "^sea";
Pattern p = Pattern.compile(regex);

Matcher m = p.matcher​("seaduck and seahorse");
m.region(12, 20);

リージョンを設定したことによって対象の文字列は "seahorse" となりますが、デフォルトの設定では ^sea は seahorse の sea にマッチするようになります。これはリージョンの設定によって対象となった文字列が、キャレット(^)やドル記号($)とマッチするためです。

// java.util.regex.*のインポートが必要です
import java.util.regex.*;

String regex  = "^sea";
Pattern p = Pattern.compile(regex);

Matcher m = p.matcher​("seaduck and seahorse");
m.region(12, 20);

System.out.println(m.find());  // true

デフォルトの動作としてはこのようになっていますが、もしリージョンを設定したことによる境界が文字列の先頭や文字列の末尾とマッチさせたくない場合は、 Matcher クラスび useAnchoringBounds メソッドを使って設定を変更します。

public Matcher useAnchoringBounds​(boolean b)

パラメータ:
b - アンカー設定境界を使用するかどうかを示すboolean。

戻り値:
この正規表現エンジン

1 番目の引数に true を指定した場合、リージョンの境界が ^ や $ にマッチします。 false を指定した場合にはマッチしません。

デフォルトの値は true となっていますので、もし変更したい場合には false を指定してください。

// java.util.regex.*のインポートが必要です
import java.util.regex.*;

String regex  = "^sea";
Pattern p = Pattern.compile(regex);

Matcher m = p.matcher​("seaduck and seahorse");
m.region(12, 20);
m.useAnchoringBounds​(false);

System.out.println(m.find());  // false

リージョンの設定によって文字列の中で対象となる範囲は変更されましたが、文字列全体の先頭や末尾とマッチするかどうかはリージョン設定前の対象の文字列を使って判断されます。

透過境界の設定を行う

メタ文字の \b は単語境界とマッチします。単語境界というのは、単語を構成する文字( a-z 、 A-Z 、 0-9 、 _ 、 Unicode 文字)とそうでない文字との境目のことです。次の例を見てください。

// java.util.regex.*のインポートが必要です
import java.util.regex.*;

String regex  = "\\bmon";
Pattern p = Pattern.compile(regex);

Matcher m = p.matcher​("salmon and monkey");

パターン \bmon は単語境界から始まり、 mon と続く文字列とマッチします。よって salmon の mon にはマッチしませんが、 monkey の mon にはマッチします。

salmon and monkey

ここで対象の文字列にリージョンを設定してみます。

// java.util.regex.*のインポートが必要です
import java.util.regex.*;

String regex  = "\\bmon";
Pattern p = Pattern.compile(regex);

Matcher m = p.matcher​("salmon and monkey");
m.region(3, 13);

リージョンを設定したことによって対象の文字列は "mon and mo" となりますが、デフォルトの設定では \bmon は salmon の mon にマッチするようになります。これはリージョンの設定によって対象となった文字列が、単語境界とマッチするためです。

// java.util.regex.*のインポートが必要です
import java.util.regex.*;

String regex  = "\\bmon";
Pattern p = Pattern.compile(regex);

Matcher m = p.matcher​("salmon and monkey");
m.region(3, 13);

System.out.println(m.find());  // true

デフォルトの動作としてはこのようになっていますが、もしリージョンを設定したことによる境界が単語境界とマッチさせたくない場合は、 Matcher クラスび useTransparentBounds メソッドを使って設定を変更します。

public Matcher useTransparentBounds​(boolean b)

パラメータ:
b - 不透明または透明の領域のどちらを使用するかを示すboolean

戻り値:
この正規表現エンジン

1 番目の引数に false を指定した場合、リージョンの境界が単語境界の \b にマッチします。 true を指定した場合にはマッチしません。

デフォルトの値は false となっていますので、もし変更したい場合には true を指定してください。

// java.util.regex.*のインポートが必要です
import java.util.regex.*;

String regex  = "\\bmon";
Pattern p = Pattern.compile(regex);

Matcher m = p.matcher​("salmon and monkey");
m.region(3, 13);
m.useTransparentBounds​(false);

System.out.println(m.find());  // false

リージョンの設定によって文字列の中で対象となる範囲は変更されましたが、単語境界とマッチするかどうかはリージョン設定前の対象の文字列を使って判断されます。

-- --

Java の正規表現でリージョン(対象文字列の中のパターンと比較する範囲)を設定する方法について解説しました。

( Written by Tatsuo Ikura )

関連記事 (一部広告含む)
Profile
profile_img

著者 / TATSUO IKURA

初心者~中級者の方を対象としたプログラミング方法や開発環境の構築の解説を行うサイトの運営を行っています。