文字クラスを使って色々な文字にマッチするパターンを記述する

広告

Java で使用できる正規表現のメタ文字のひとつである文字クラスの使い方について解説します。文字クラスでは固定の文字列の他に、任意の一文字にマッチするパターンや、複数の候補のいずれか一つの文字にマッチするパターンを記述することができます。

記述した文字にマッチする

パターンの中に文字を記述した場合は、その文字そのものとマッチします。例えば次のようなパターンは A で始まり、次に B が続き、最後に C が続く文字列にマッチします

String regex = "ABC";

ABC や XXABC 、 0ABC9 などにマッチします。 AMMBC や ACB にはマッチしません。

ABC
〇 XXABC
〇 0ABC9
✕ AMMBC
✕ ACB

実際にサンプルで試してみます。下記では "Sun" という文字列とマッチするかどうかを検索しています。

import java.util.regex.*;

class JSample8_1{
  public static void main(String[] args){
    String regex = "Sun";
    Pattern p = Pattern.compile(regex);

    Matcher m1 = p.matcher("Today is Sunday");
    System.out.println(m1.find());  // true

    Matcher m2 = p.matcher("Sunrise");
    System.out.println(m2.find());  // true

    Matcher m3 = p.matcher("Ham Sandwich");
    System.out.println(m3.find());  // false
  }
}

任意の一文字(.)

メタ文字のひとつであるドット(.)は任意の一文字(例外あり)にマッチします。

.

ただし例外があります。 DOTALL フラグが設定されていない場合、 \n などの行末記号にはマッチしません。(行末記号とは行の末尾を表す文字のことです)。行末記号については「行末記号について」を参照してください。

例えば次のようなパターンは A で始まり、任意の 1 文字が続き、そのあとに B が続く文字列にマッチします。

String regex = "A.B";

AXB や CA5BC などにマッチします。 AETB や AB にはマッチしません。

AXB
〇 CA5BC
✕ AETB
✕ AB

例えば次のようなパターンは A で始まり、任意の 2 文字が続き、そのあとに B が続く文字列にマッチします。

String regex = "A..B";

AETB や CA01BC などにマッチします。 AXB や AB にはマッチしません。

AETB
〇 CA01BC
✕ AXB
✕ AB

実際にサンプルで試してみます。下記では "S"で始まり、任意の文字が 2 つ続き、最後に"d"で終わる文字列とマッチするかどうか検索しています。

import java.util.regex.*;

class JSample8_2{
  public static void main(String[] args){
    String regex = "S..d";
    Pattern p = Pattern.compile(regex);

    Matcher m1 = p.matcher("Today is Sunday");
    System.out.println(m1.find());  // true

    Matcher m2 = p.matcher("Sunrise");
    System.out.println(m2.find());  // false

    Matcher m3 = p.matcher("Ham Sandwich");
    System.out.println(m3.find());  // true
  }
}

角括弧の中の一文字([ABC])

角括弧([ABC])は角括弧の中に記述した複数の文字のいずれか一つにマッチさせる場合に使用するメタ文字です。

[ABC]

例えば次のようなパターンは A で始まり、 [ から ] の間に記述された D 、 E 、 F のいずれかの一文字が続き、そのあとに B が続く文字列にマッチします。

String regex = "A[DEF]B";

ADB や oAEBo などにマッチします。 AXB や AdB にはマッチしません。

ADB
〇 oAEBo
✕ AXB
✕ AdB

実際にサンプルで試してみます。下記では"Sun"または"sun"とマッチするかどうか検索しています。

import java.util.regex.*;

class JSample8_3{
  public static void main(String[] args){
    String regex = "[Ss]un";
    Pattern p = Pattern.compile(regex);

    Matcher m1 = p.matcher("Today is Sunday");
    System.out.println(m1.find());  // true

    Matcher m2 = p.matcher("Sunrise");
    System.out.println(m2.find());  // true

    Matcher m3 = p.matcher("Ham Sandwich");
    System.out.println(m3.find());  // false
  }
}

角括弧の否定([^ABC])

角括弧([ABC])の先頭に否定を表すキャレット(^)を記述した場合、角括弧の中に記述した複数の文字のいずれにも一致しない場合にマッチします。

[^ABC]

例えば次のようなパターンは A で始まり、 [ から ] の間に記述された D 、 E 、 F のいずれにも一致しない一文字が続き、そのあとに B が続く文字列にマッチします。

String regex = "A[^DEF]B";

ご注意いただきたいのは ^ のすぐあとの文字だけを否定するのではなく、 [ から ] に記述されたすべての文字を否定します。

AOB や oAdBo にはマッチします。 ADB や AEB にはマッチしません。

AOB
〇 oAdBo
✕ ADB
✕ AEB

実際にサンプルで試してみます。下記では 199 のあとに 0 、 1 、 2 、 3 、 4 のいずれかの文字ではない文字が続く文字列とマッチするかどうか検索しています。

import java.util.regex.*;

class JSample8_4{
  public static void main(String[] args){
    String regex = "199[^01234]";
    Pattern p = Pattern.compile(regex);

    Matcher m1 = p.matcher("My birthday is 1998/03/12");
    System.out.println(m1.find());  // true

    Matcher m2 = p.matcher("Graduated in 1994");
    System.out.println(m2.find());  // false

    Matcher m3 = p.matcher("price of eraser is 199yen");
    System.out.println(m3.find());  // true
  }
}

角括弧の範囲指定([A-Z])

角括弧([ABC])の中でハイフン(-)を記述すると、ハイフンの左側から右側までの範囲に含まれる連続するいずれかの文字にマッチします。例えば次のように記述することができます。

[0-9]  0 から 9 までのいずれかの数値
[a-z]  a から z までのいずれかの文字
[E-M]  E から M までのいずれかの文字

例えば次の二つのパターンは同じ文字にマッチします。

String regex1 = "[3-8]";
String regex2 = "[345678]";

[ から ] の中に複数の範囲を記述したり、通常の文字の指定と組み合わせることもできます。次のパターンは a から e 、 g 、 m 、 x から z までのいずれかの文字にマッチします。

String regex1 = "[a-egmx-z]";
String regex2 = "[abcdegmxyz]";

英数字のいずれかの文字にマッチするパターンとして次のような記述がよく使われます。(英数字は a から z 、 A から Z 、 0 から 9 のいずれかの文字です)。

String regex = "[0-9a-zA-Z]";

このように連続する文字の中のいずれかひとつにマッチさせたい場合にこの書式は便利です。

実際にサンプルで試してみます。下記では 199 のあとに 0 から 6 のいずれかの文字が続く文字列とマッチするかどうか検索しています。

import java.util.regex.*;

class JSample8_5{
  public static void main(String[] args){
    String regex = "199[0-6]";
    Pattern p = Pattern.compile(regex);

    Matcher m1 = p.matcher("My birthday is 1998/03/12");
    System.out.println(m1.find());  // false

    Matcher m2 = p.matcher("Graduated in 1994");
    System.out.println(m2.find());  // true

    Matcher m3 = p.matcher("price of eraser is 199yen");
    System.out.println(m3.find());  // false
  }
}

角括弧の結合、交差、減算

角括弧[]の中にさらに角括弧[]を記述することで、次のような範囲の指定方法が利用できます。

結合

[A-C[D-F]] のように記述した場合、 A から C 、または D から F までのいずれかの文字とマッチします。これは [A-CD-F] と書いた場合と同じです。

[A-C[D-F]]  A から C または D から F

交差

[A-F&&[D-H]] のように記述した場合、 A から F までと D から H までの両方の範囲に含まれる D から F までのいずれかの文字とマッチします。

[A-F&&[D-H]]  D から F

減算

[A-H&&[^D-F]] のように記述した場合、 A から H までの中で D から F を除いた範囲に含まれる A から C 、または G から H までのいずれかの文字とマッチします。

[A-H&&[^D-F]]  A から C または G から H

あまり利用される機会はないかもしれませんが、こういった記述方法もあるということだけ覚えておかれてください。

定義済みの文字クラス

文字クラスでは [ から ] の中に文字の範囲を記述することで多くの文字の中のいずれかの文字とマッチするパターンを記述することができますが、特によく使用するものについては定義済みの文字クラスが用意されています。 Java で利用可能なものは次の通りです。

\d	数字: [0-9]
\D	数字以外: [^0-9]
\h	水平方向の空白文字:
    [ \t\xA0\u1680\u180e\u2000-\u200a\u202f\u205f\u3000]
\H	水平方向以外の空白文字: [^\h]
\s	空白文字: [\t\n\x0B\f\r]
\S	非空白文字: [^\s]
\v	垂直方向の空白文字: [\n\x0B\f\r\x85\u2028\u2029]
\V	垂直方向以外の空白文字: [^\v]
\w	単語文字: [a-zA-Z_0-9]
\W	非単語文字: [^\w]

\D は \d の否定のように大文字のものは小文字のものの否定になっています。空白文字(\s)は半角スペース以外に改行(\n)やタブ(\t)など空白に相当する文字にマッチします。

定義済みの文字クラスを文字列の中で記述する場合はバックスラッシュ(\)をバックススラッシュでエスケープする必要がある点に注意してください。(詳しくは「文字列の中で正規表現のメタ文字を記述する場合」をご覧ください)。

例えば次の二つのパターンは同じ文字にマッチします。

String regex1 = "[0-9]";
String regex2 = "\\d";

記述方法が異なるだけでマッチする文字は同じです。定義済みの文字クラスが用意されているものについては定義済みの文字クラスを使用することでよりコンパクトにパターンを記述することができます。

実際にサンプルで試してみます。下記では 数値が 3 つ続いたあと、 - が続き、そのあとで今度は数値が 4 つ続く文字列とマッチするかどうか検索しています。

import java.util.regex.*;

class JSample8_6{
  public static void main(String[] args){
    String regex = "\\d{3}-\\d{4}";
    Pattern p = Pattern.compile(regex);

    Matcher m = p.matcher("〒123-4567 東京都千代田区");
    if (m.find()){
      System.out.println("マッチしました");
      System.out.println(m.group());  // 123-4567
    }
  }
}

エスケープシーケンスを使った特殊な文字

文字クラスとは違いますが、改行やタブなどキーボードから入力できないような特殊な文字にマッチするパターンを記述するため、バックスラッシュ(\)と文字を組み合わせたメタ文字が用意されています。

\t  タブ文字(「\u0009」)
\n  改行文字(「\u000A」)
\r  キャリッジ・リターン文字(「\u000D」)
\f  用紙送り文字(「\u000C」)
\a  警告(ベル)文字(「\u0007」)
\e  エスケープ文字(「\u001B」)
\cx     xに対応する制御文字
\0n     8進値0nを持つ文字(0 <= n <= 7)
\0nn    8進値0nnを持つ文字(0 <= n <= 7)
\0mnn   8進値0mnnを持つ文字(0 <= m <= 3, 0 <= n <= 7)
\xhh    16進値 0xhhを持つ文字 
\uhhhh  16進値 0xhhhhを持つ文字 
\x{h...h}  16進値0xh...hを持つ文字
\N{name}  Unicode文字の名前が'name'の文字

これらを文字を文字列の中で記述する場合はバックスラッシュ(\)をバックススラッシュでエスケープする必要がある点に注意してください。

行末記号について

正規表現では次の 1 文字または 2 文字を行末記号として扱います。行末記号とは行の末尾を表す文字のことです。

\n      改行文字
\r\n    改行文字+キャリッジ・リターン文字
\r      キャリッジ・リターン文字
\u0085  次行文字
\u2028  行区切り文字
\u2029  段落区切り文字

UNIX_LINES モードが有効な場合は、改行文字( \n )だけが行末記号として扱われます。

文字クラスの . はすべての行末記号にはマッチしません。ただし DOTALL フラグが有効な場合は行末記号にもマッチします。詳しくは DOTALL フラグのページで解説します。

また行末記号は文字列の先頭を表す ^ や文字列の末尾を表す $ とはマッチしません。ただし MULTILINE モードが有効な場合は行末記号にもマッチします。詳しくは MULTILINE フラグのページで解説します。

-- --

Java で使用できる正規表現のメタ文字のひとつである文字クラスの使い方について解説しました。

( Written by Tatsuo Ikura )

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

著者 / TATSUO IKURA

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