|
|
いずれかの文字に一致(文字クラス) |
H.Kamifuji . |
複数の文字を並べて記述し、どれか一つにマッチするパターンの記述方法について確認します。選択の場合と異なりマッチする対象が1文字ですが、連続した文字の集まりを簡潔に記述する方法などが用意されています。 当ページでは、Linux CentOS7 の Gnome で動作テストしています。 現在(2021/08)では、JDK-16.0.2 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2021/11)では、JDK-17.0.1 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2023/04)では、JDK-20.0.1 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2024/10)では、JDK-23 にアップされています。一部、上位互換について、見直しを行っていきます。 |
|
文字クラスとは候補となる1つの文字を列挙し、そのいずれかに一致する場合にマッチするパターンを記述する時に使用します。 書式は次の通りです。 "[abc]"候補となる文字を並べて記述し、全体をブラケット([])(角括弧とも言う)で囲います。選択と異なり候補は必ず1文字です。その為候補と候補の間には区切り文字などは不用です。上記は"a"、"b"、"c"のどれかが含まれる文字列にマッチします。 例として次のようなパターンを定義します。 "2000[5678]"ターゲット文字列毎にこのパターンがマッチするかどうかを次に例として記述します。 × 2004 ○ 2005 ○ 2006 ○ 2007 ○ 2008 × 2009なお文字クラスは選択を使って次のように記述した場合と同じです。 "2000(5|6|7|8)"文字クラスは候補が1つの文字しか記載できませんが、その代わり区切り線を記述する必要がありません。場合に応じて使い分けて下さい。 具体的には次のように記述します。 String str = "Document created by 20090801"; String regex = "2000[5678]"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(str); if (m.find()){ System.out.println("マッチしました"); }else{ System.out.println("マッチしません"); }上記の場合はマッチしません。 では実際に試してみます。 サンプルプログラム下記のサンプルを実行してみよう。import java.util.regex.Pattern; import java.util.regex.Matcher; class JSample1_1{ public static void main(String args[]){ String str1 = "Japan Cup"; String str2 = "japanese noodle"; String str3 = "jp code"; String regex = "[J|j]apan"; Pattern p = Pattern.compile(regex); System.out.println("パターン : " + regex); check(p, str1); check(p, str2); check(p, str3); } private static void check(Pattern p, String target){ Matcher m = p.matcher(target); if (m.find()){ System.out.println("○ " + target + " [" + m.group() + "]" ); }else{ System.out.println("× " + target); } } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Char]$ javac JSample1_1.java [xxxxxxxx@dddddddddd Char]$ java JSample1_1 パターン : [J|j]apan ○ Japan Cup [Japan] ○ japanese noodle [japan] × jp code [xxxxxxxx@dddddddddd Char]$ |
文字クラスを使用する場合、マッチさせたい文字を全て列挙します。列挙する文字ばバラバラの場合は一つ一つ記述するしかありませんが、例えば数字の0から9や文字のaからzなどのように連続した文字を指定したい場合があります。このような場合にはメタ文字のハイフン(-)を使い範囲指定の形式で記述できます。 書式は次の通りです。 "[0-9]"文字クラスの中では"-"は特別な意味を持ち範囲を表すために使われます。上記は"a"から"e"までの文字を順に記載したものと同じ扱いになります。よって上記は次のように記述した場合と同じです。 "[0123456789]"同じようにアルファベットについても同じように範囲で指定することができます。例えば次の2つのパターンは同じ扱いとなります。 "[a-z]" "[abcdefghijklmnopqrstuvwxyz]"アルファベットの大文字についても同様です。 "[A-Z]" "[ABCDEFGHIJKLMNOPQRSTUVWXY]"もちろん先頭から最後までである必要はありません。4から7までとかDからMまでのように範囲指定することも可能です。 "[4-7]" "[D-M]"また同じ文字クラスの中に範囲と文字を組み合わせて記述することも可能です。 "[AD-MXY]""[AD-MXY]"は"[ADEFGHIJKLMXY]"と記載した場合と同じです。 範囲を複数文字クラス内に記述することもできます。 "[0-9a-zA-Z]""[0-9a-zA-Z]"は0から9、aからz、AからZのいずれかにの文字が含まれる文字列にマッチします。 具体的には次のように記述します。 String str = "Document No.7"; String regex = "No.[0-9]"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(str); if (m.find()){ System.out.println("マッチしました"); }else{ System.out.println("マッチしません"); }上記の場合はマッチします。 なおこのように文字クラスの中で"-"は特別な意味を持ちますので、文字クラスの中で候補の文字として"-"を使用する場合はエスケープ処理をして下さい。 では実際に試してみます。 サンプルプログラム下記のサンプルを実行してみよう。import java.util.regex.Pattern; import java.util.regex.Matcher; class JSample2_1{ public static void main(String args[]){ String str1 = "0x08"; String str2 = "0xA5"; String str3 = "0xT2"; String str4 = "0x3e"; String regex1 = "0x[0-9A-F][0-9A-F]"; Pattern p1 = Pattern.compile(regex1); String regex2 = "0x[0-9a-fA-F][0-9a-fA-F]"; Pattern p2 = Pattern.compile(regex2); System.out.println("パターン : " + regex1); check(p1, str1); check(p1, str2); check(p1, str3); check(p1, str4); System.out.println("パターン : " + regex2); check(p2, str1); check(p2, str2); check(p2, str3); check(p2, str4); } private static void check(Pattern p, String target){ Matcher m = p.matcher(target); if (m.find()){ System.out.println("○ " + target + " [" + m.group() + "]" ); }else{ System.out.println("× " + target); } } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Char]$ javac JSample2_1.java [xxxxxxxx@dddddddddd Char]$ java JSample2_1 パターン : 0x[0-9A-F][0-9A-F] ○ 0x08 [0x08] ○ 0xA5 [0xA5] × 0xT2 × 0x3e パターン : 0x[0-9a-fA-F][0-9a-fA-F] ○ 0x08 [0x08] ○ 0xA5 [0xA5] × 0xT2 ○ 0x3e [0x3e] [xxxxxxxx@dddddddddd Char]$ |
文字クラスはマッチさせたい候補の文字を列挙して使いますが、列挙した文字以外の全ての文字にマッチさせることも可能です。このような場合にはメタ文字の"^"を使います。 書式は次の通りです。 "[^abc]"上記の場合であれば"a"、"b"、"c"以外の全ての文字が含まれる文字列にマッチします。 否定を使う場合には必ず文字クラスの先頭に"^"を記述します。文字クラスの先頭以外に"^"が記述されていた場合は文字の"^"として扱われます。例えば次のような記述を考えてみます。 "[ab^0-9]"例えば上記では"a"、"b"、0から9以外、と言う意味ではなく、"a"、"b"、"^"、"0から9"の文字クラスです。 逆に言えば文字クラスの中で候補の一つとして"^"を使いたい場合は、先頭以外の場所に記載して下さい。先頭以外で使われた場合は特別な意味を持たないためエスケープ処理も不要です。 具体的には次のように記述します。 String str = "Document No.7"; String regex = "No.[^0-9]"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(str); if (m.find()){ System.out.println("マッチしました"); }else{ System.out.println("マッチしません"); }上記の場合はマッチしません。 では実際に試してみます。 サンプルプログラム下記のサンプルを実行してみよう。import java.util.regex.Pattern; import java.util.regex.Matcher; class JSample3_1{ public static void main(String args[]){ String str1 = "0x08"; String str2 = "0xT2"; String str3 = "0x3e"; String str4 = "0x5@"; String regex = "0x[^e-zE-Z]"; Pattern p = Pattern.compile(regex); System.out.println("パターン : " + regex); check(p, str1); check(p, str2); check(p, str3); check(p, str4); } private static void check(Pattern p, String target){ Matcher m = p.matcher(target); if (m.find()){ System.out.println("○ " + target + " [" + m.group() + "]" ); }else{ System.out.println("× " + target); } } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Char]$ javac JSample3_1.java [xxxxxxxx@dddddddddd Char]$ java JSample3_1 パターン : 0x[^e-zE-Z] ○ 0x08 [0x0] × 0xT2 ○ 0x3e [0x3] ○ 0x5@ [0x5] [xxxxxxxx@dddddddddd Char]$文字クラスの否定の場合は、思いがけない文字に一致する場合がありますので注意して下さい。例えば"^0-9"では数字以外ということなのでアルファベットにマッチするように思ってしまう場合もありますが、アルファベット以外の様々な記号にも一致します。 |
Javaの文字クラスでは集合演算を行うことができます。 まずはORです。書式は次の通りです。 "[a-c[f-h]]" "[[a-c]f-h]" "[[a-c][f-h]]"上記は全て同じで"[a-cf-h]"と単に記載した場合と同じです。つまり「a〜c」と「f〜h」のいずれの文字に一致する文字列にマッチします。このように文字クラスの中に他の文字クラスを記載するとORのように働きます。あえてこのような記載の仕方をする意味は今のところ思いつきません。 次はANDです。書式は次の通りです。 "[a-c&&[cde]]" "[a-c&&[c-e]]" "[[a-c]&&[c-e]]"上記は「a〜c」且つ「c〜e」となります。つまりこの場合は"[c]"と書いた場合と同じです。このように文字クラスの中で他の文字クラスとメタ文字の"&&"を使ってつなげるとANDのように働きます。 ANDの便利な点は次のような記述が行えることです。 "[a-z&&[^f-m]]"上記は「a〜z」且つ「f〜m以外」となります。つまり「a〜z」の中で「f〜m」の部分を除いたものになります。このように否定の文字クラスとのANDを取ることで、あたかも差分を取ったような文字クラスを定義することができます。 具体的には次のように記述します。 String str = "Document No.7"; String regex = "No.[0-9&&[^2-4]"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(str); if (m.find()){ System.out.println("マッチしました"); }else{ System.out.println("マッチしません"); }上記の場合はマッチします。 では実際に試してみます。 サンプルプログラム下記のサンプルを実行してみよう。import java.util.regex.Pattern; import java.util.regex.Matcher; class JSample4_1{ public static void main(String args[]){ String str1 = "bbb"; String str2 = "ggg"; String str3 = "nnn"; String regex1 = "[[a-d][x-z]]"; Pattern p1 = Pattern.compile(regex1); String regex2 = "[[a-m]&&[d-z]]"; Pattern p2 = Pattern.compile(regex2); String regex3 = "[[a-z]&&[^f-m]]"; Pattern p3 = Pattern.compile(regex3); System.out.println("パターン : " + regex1); check(p1, str1); check(p1, str2); check(p1, str3); System.out.println("パターン : " + regex2); check(p2, str1); check(p2, str2); check(p2, str3); System.out.println("パターン : " + regex3); check(p3, str1); check(p3, str2); check(p3, str3); } private static void check(Pattern p, String target){ Matcher m = p.matcher(target); if (m.find()){ System.out.println("○ " + target + " [" + m.group() + "]" ); }else{ System.out.println("× " + target); } } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Char]$ javac JSample4_1.java [xxxxxxxx@dddddddddd Char]$ java JSample4_1 パターン : [[a-d][x-z]] ○ bbb [b] × ggg × nnn パターン : [[a-m]&&[d-z]] × bbb ○ ggg [g] × nnn パターン : [[a-z]&&[^f-m]] ○ bbb [b] × ggg ○ nnn [n] [xxxxxxxx@dddddddddd Char]$ |
文字クラスでは比較的よく利用される組み合わせがあります。例えば数字を表す"[0-9]"などです。このような比較的よく利用される文字クラスには略記が定義されています。ここでは文字クラスの略記法について確認します。 数字を表す"\d"と"\D""\d"は数字を表す略記法です。文字クラスの"[0-9]"に該当します。"\d" "[\d]" "[0-9]"上記は0〜9のいずれかの文字にマッチします。"\d"は文字クラスを表すブラケット[]の外側でも記述できますが、文字クラスの中の1つの候補としてブラケット内にも記述することが出来ます。 "[\dabc]"上記は"0〜9"と"a"、"b"のいずれかの文字にマッチします。 また"\D"は数字以外を表す略記法です。文字クラスの"[^0-9]"または"[^\d]"に該当します。 "\D" "[\D]" "[^\d]" "[^0-9]"上記は0〜9以外のいずれかの文字にマッチします。 任意の桁の数字にマッチするパターンは次のように記述することができます。 "[\d+]" 単語構成文字を表す"\w"と"\W""\w"は単語構成文字を表す略記法です。文字クラスの"[0-9a-zA-Z_]"に該当します。アルファベットのaからzとAからZ、数字の0から9、そして"_"の集合です。"\w" "[\w]" "[a-zA-Z0-9_]"上記は0〜9、a〜z、A〜Z、"_"のいずれかの文字にマッチします。"\w"は文字クラスを表すブラケット[]の外側でも記述できますが、文字クラスの中の1つの候補としてブラケット内にも記述することが出来ます。 また"\W"は単語構成文字以外を表す略記法です。文字クラスの"[^0-9a-zA-Z_]"または"[^\w]"に該当します。 "\W" "[\W]" "[^\w]" "[^a-zA-Z0-9_]"上記は単語構成文字以外の全ての文字にマッチします。 任意の桁の単語構成文字からなら文字列にマッチするパターンは次のように記述することができます。 "[\w+]" 空白を表す"\s"と"\S""\s"は空白を表す略記法です。文字クラスの"[ \t\n\x0B\f\r]"に該当します。空白" "、タブ("\t")、改行("\n")、垂直タブ("\x0B")、用紙送り文字("\f")、キャリッジリターン("\r")の集合です。"\s" "[\s]" "[ \t\n\x0B\f\r]"上記は空白と扱われる各文字ののいずれかの文字にマッチします。"\s"は文字クラスを表すブラケット[]の外側でも記述できますが、文字クラスの中の1つの候補としてブラケット内にも記述することが出来ます。 また"\S"は空白文字以外を表す略記法です。文字クラスの"[^ \t\n\x0B\f\r]"または"[^\s]"に該当します。 "\S" "[\S]" "[^\s]" "[^ \t\n\x0B\f\r]"上記は空白文字以外の全ての文字にマッチします。 "\s"を使い任意の連続する空白文字に文字にマッチするパターンは次のように記述できます。 "[\s+]" POSIX 文字クラス定義済みのクラス以外にPOSIX 文字クラスと呼ばれるものも用意されています。次のようなものがあります。\p{Lower} 小文字の英字:[a-z] \p{Upper} 大文字の英字: [A-Z] \p{ASCII} すべての ASCII 文字: [\x00-\x7F] \p{Alpha} 英字: [\p{Lower}\p{Upper}] \p{Digit} 10 進数字: [0-9] \p{Alnum} 英数字: [\p{Alpha}\p{Digit}] \p{Punct} 句読文字:!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ のいずれか \p{Graph} 表示できる文字:[\p{Alnum}\p{Punct}] \p{Print} プリント可能文字:[\p{Graph}\x20] \p{Blank} 空白またはタブ:[ \t] \p{Cntrl} 制御文字:[\x00-\x1F\x7F] \p{XDigit} 16 進数字:[0-9a-fA-F] \p{Space} 空白文字:[ \t\n\x0B\f\r]例えば"\w"と記述する代わりに"\p{Space}"と記述しても同じです。 ただしこのPOSIX文字クラスはUS-ASCIIのみで使用できます。 では実際に試してみます。 サンプルプログラム下記のサンプルを実行してみよう。import java.util.regex.Pattern; import java.util.regex.Matcher; class JSample5_1{ public static void main(String args[]){ String str1 = "example.jp"; String str2 = "example.co.jp"; String str3 = "example.com"; String regex = "\\w+(\\.\\w)*\\.jp"; Pattern p = Pattern.compile(regex); System.out.println("パターン : " + regex); check(p, str1); check(p, str2); check(p, str3); } private static void check(Pattern p, String target){ Matcher m = p.matcher(target); if (m.find()){ System.out.println("○ " + target + " [" + m.group() + "]" ); }else{ System.out.println("× " + target); } } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Char]$ javac JSample5_1.java [xxxxxxxx@dddddddddd Char]$ java JSample5_1 パターン : \w+(\.\w)*\.jp ○ example.jp [example.jp] ○ example.co.jp [co.jp] × example.com [xxxxxxxx@dddddddddd Char]$エスケープがされているので分かりにくいですが"\\w+(\\.\\w)*\\.jp"は"\w"が1回以上続き、文字の"."か"\w"のいずれかが0回以上続き、さらに文字の"."と文字列の"jp"が続くパターンです。 |
|