こんにちは!エンジニアの中沢です。
Javaには文字列から特定のパターンを検索して、一致する文字列があるかをチェックするための正規表現があります。
正規表現を使えば文字列の中から数字だけを抽出したり、メールアドレスを抽出することができます。
この記事では、
- Javaの正規表現とは
- 正規表現の使い方
- 一致するかチェックする方法
- 一致する文字を抽出する方法
- 特殊文字のエスケープ処理について
などの基本的な内容から、応用的な使い方に関しても解説していきます。
さらに、数字やメールアドレスなどのよく使う正規表現の書き方のサンプル一覧もあるので、忘れてしまったらこちらを確認してください。
今回はこれらの方法を覚えるために、正規表現のさまざまな使い方をわかりやすく解説します!
なお、Javaの記事については、こちらにまとめています。
Javaの正規表現とは
正規表現とは文字列のパターンを一つの形式でまとめて表現するために使うもののことです。
例えば、文字列の中から”123-4567”のような郵便番号を検索したい場合には次のような正規表現の記述を使います。
[0-9]{3}-[0-9]{4}
この正規表現の記述の意味は、0から9の数字が3回続いた後に”-”(ハイフン)があり、その次に0から9の数字が4回続いたら郵便番号だと判断して一致する判定をします。
主な正規表現の記号と意味については以下の表の通りです。
記号 | 記号の説明 | 例 | 例の説明 |
---|---|---|---|
. | 任意の1文字。改行文字は除く。 | .+ | 任意の文字列 |
* | 直前の1文字の0回以上の繰り返しと一致 | hoge* | hogeもしくはhogee...と一致 |
^ | 行の先頭 | ^[0-9] | 行頭が数字 |
$ | 行の末尾 | ^.{10}$ | 10文字の行 |
[ ] | カッコ内の任意の1文字と一致。「-」で範囲指定可。 | [a-z] | 小文字のアルファベット1文字と一致 |
[^ ] | カッコ内の任意の1文字と不一致。「-」で範囲指定可。 | [^A-Z] | 大文字のアルファベット以外 |
+ | 直前の文字の1個以上の繰り返しと一致 | hoge+ | hogee...と一致 |
? | 直前の文字が0個または1個の場合に一致 | hoge? | hogeもしくはhogと一致 |
{ } | カッコ内の数値の繰り返しと一致 | {n} | 直前の文字のn個の繰り返しと一致 |
同上 | {,n} | 直前の文字のn個以下の繰り返しと一致 | |
同上 | {m,} | 直前の文字のm個以上の繰り返しと一致 | |
同上 | {m,n} | 直前の文字のm個以上、n個以下の繰り返しと一致 | |
| | 直前、直後どちらかのパターンに一致 | hoge|piyo | hogeまたはpiyo |
( ) | カッコ内をグループ化。マッチした内容は参照可。 | ー | ー |
正規表現の使い方
ここでは正規表現の使い方をサンプルコードを交えて解説していきます。
matchesメソッドでチェックする方法
初めに正規表現で指定したパターンと一致するかを確認する簡単な方法として、Stringクラスのmatchesメソッドの使い方を解説します。
matchesメソッドは指定した文字列と正規表現が完全に一致した場合に”true”を返します。一部が一致しただけでは”false”を返すので注意してください!
Stringクラスのmatchesメソッドの使い方を次のプログラムで確認してみましょう。
[matcheメソッドのサンプルコード]
public class Main { public static void main(String[] args) { // 検索する文字列を用意 String str = "東京都千代田区 123-4567"; System.out.println(str.matches(".*[0-9]{3}-[0-9]{4}.*")); System.out.println(str.matches("[0-9]{3}-[0-9]{4}")); System.out.println(str.matches(".*123-4567.*")); System.out.println(str.matches("123-4567")); } }
[実行結果]
true false true false
このプログラムではmatchesメソッドを使って、正規表現で表現した文字列が含まれているかを判定しています。matchesメソッドは完全一致のときに”true”を返すので、検索したい文字列の前後に他の文字があると”false”を返します。
そのため、正規表現のパターンの前後に「任意の文字がいくつかある」という意味の「.*」を追加して完全一致させることで”true”を返しています。
Stringクラスのmatchesメソッドの使い方はこちらで詳しく解説しているので、ぜひ確認してください。
パターンの作り方(Patternクラス)
ここではPatternクラスを使って正規表現のパターンを作る方法を解説します。
正規表現のパターンオブジェクトを作るには、Patternクラスのcompileメソッドの引数に正規表現のパターンを指定します。
次に、Patternクラスのmatcherメソッドの引数にパターンとマッチさせる文字列を指定してMatcherオブジェクトを作成します。
正規表現のパターンを作る方法を次のプログラムで確認してみましょう。
[正規表現のパターンの作り方のサンプルコード]
import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { // 検索する文字列を用意 String str = "東京都千代田区 123-4567"; // 正規表現のパターンを作成 Pattern p = Pattern.compile("[0-9]{3}-[0-9]{4}"); Matcher m = p.matcher(str); } }
このプログラムでは、文字列「東京都千代田区 123-4567」と正規表現のパターン「[0-9]{3}-[0-9]{4}」のMatcherオブジェクトを作成しています。
このMatcherオブジェクトを使ってチェックや抽出する方法をこれから解説していきます!
一致するかチェックする方法(Matcherクラス)
ここではMatcherクラスのfindメソッドを使って、文字列が正規表現のパターンに一致するかをチェックする方法を解説します。
Matcherクラスのfindメソッドは、文字列の中に正規表現のパターンが含まれる場合に”true”を返し、それ以外の場合には”false”を返します。
次のプログラムでfindメソッドの使い方を確認してみましょう。
[findメソッドの使い方のサンプルコード]
import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { // 検索する文字列を用意 String str = "東京都千代田区 123-4567"; // 正規表現のパターンを作成 Pattern p = Pattern.compile("[0-9]{3}-[0-9]{4}"); Matcher m = p.matcher(str); System.out.println(m.find()); } }
[実行結果]
true
このプログラムでは文字列「東京都千代田区 123-4567」の中に、正規表現の郵便番号のパターン「[0-9]{3}-[0-9]{4}」が含まれているため”true”を返しています。
一致する複数の文字をすべて抽出する方法
ここではMatcherクラスのgroupメソッドを使って、正規表現のパターンに一致した文字列を抽出する方法を解説します。
groupメソッドはfindメソッドで一致した文字列を返します。次のプログラムで確認してみましょう。
[groupメソッドのサンプルコード]
import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { // 検索する文字列を用意 String str = "東京都千代田区 123-4567, 東京都渋谷区 111-2233"; // 正規表現のパターンを作成 Pattern p = Pattern.compile("[0-9]{3}-[0-9]{4}"); Matcher m = p.matcher(str); while (m.find()) { System.out.println("一致した部分は : " + m.group()); } } }
[実行結果]
一致した部分は : 123-4567 一致した部分は : 111-2233
このプログラムでは、findメソッドを使って郵便番号に一致した文字列をgroupメソッドで抽出して表示しています。
findメソッドは一致した場合に”true”を返すので、while文のループで一致する文字列がなくなるまで検索と表示を繰り返しています。このプログラムの実行結果から、正規表現を使って一致する複数の文字をすべて抽出できることが確認できました!
特殊文字のエスケープ処理について
正規表現で使う特殊な意味を持った記号をただの文字として使う場合には、エスケープ処理をする必要があります。
エスケープ処理をするには記号の前に(バックスラッシュ)を付けるだけでOKです。ただし、(バックスラッシュ)を使うには「」のように2回続けて記述する必要があるので注意してください!
この(バックスラッシュ)は環境によっては¥(円記号)になりますがどちらでも問題ありません。エスケープ処理が必要な記号は次のとおりです。
* + . ? { } ( ) [ ] ^ $ – |
エスケープ処理の例は以下のとおりです。
→ * → * {} → {}
正規表現の書き方サンプル一覧
ここでは正規表現でよく使われるパターンのサンプルを解説します。
数字のチェック
数字のチェックをする正規表現のパターンは次のとおりです。
^[0-9]+$
次のプログラムで確認してみましょう。
[数字のチェックをするサンプルコード]
import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { // 検索する文字列を用意 String str = "123"; // 正規表現のパターンを作成 Pattern p = Pattern.compile("^[0-9]+$"); Matcher m = p.matcher(str); System.out.println(m.find()); } }
[実行結果]
true
英数字のチェック
英数字のチェックをする正規表現のパターンは次のとおりです。
^[0-9a-zA-Z]+$
次のプログラムで確認してみましょう。
[英数字のチェックをするサンプルコード]
import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { // 検索する文字列を用意 String str = "SAMURAI123"; // 正規表現のパターンを作成 Pattern p = Pattern.compile("^[0-9a-zA-Z]+$"); Matcher m = p.matcher(str); System.out.println(m.find()); } }
[実行結果]
true
日付のチェック
日付のチェックをする正規表現のパターンは次のとおりです。
^[0-9]{4}/[0-9]{2}/[0-9]{2}$
日付を正規表現で厳密にチェックしようとすると、うるう年などがあり大変なので、厳密にチェックする場合は日付型のオブジェクトにしてチェックする方が実用的です。
日付が正しいかをSimpleDateFormatクラスのsetLenientメソッドを使用して厳密にチェックする方法はこちらで詳しく解説しているので参考にしてください。
正規表現で簡易的にチェックする方法を次のプログラムで確認してみましょう。
[日付のチェックをするサンプルコード]
import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { // 検索する文字列を用意 String str = "2017/06/28"; // 正規表現のパターンを作成 Pattern p = Pattern.compile("^[0-9]{4}/[0-9]{2}/[0-9]{2}$"); Matcher m = p.matcher(str); System.out.println(m.find()); } }
[実行結果]
true
電話番号のチェック
電話番号のチェックをする正規表現のパターンは次のとおりです。
^[0-9]{3}-[0-9]{4}-[0-9]{4}$
区切りや桁数を変えることで他のパターンの電話番号にも対応できます。
次のプログラムで確認してみましょう。
[電話番号のチェックをするサンプルコード]
import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { // 検索する文字列を用意 String str = "090-1234-5678"; // 正規表現のパターンを作成 Pattern p = Pattern.compile("^[0-9]{3}-[0-9]{4}-[0-9]{4}$"); Matcher m = p.matcher(str); System.out.println(m.find()); } }
[実行結果]
true
郵便番号のチェック
郵便番号のチェックをする正規表現のパターンは次のとおりです。
^[0-9]{3}-[0-9]{4}$
次のプログラムで確認してみましょう。
[郵便番号のチェックをするサンプルコード]
import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { // 検索する文字列を用意 String str = "123-4567"; // 正規表現のパターンを作成 Pattern p = Pattern.compile("^[0-9]{3}-[0-9]{4}$"); Matcher m = p.matcher(str); System.out.println(m.find()); } }
[実行結果]
true
IPアドレス(IPv4, IPv6)のチェック
ここではIPアドレスのチェックの方法をIPv4とIPv6でそれぞれ解説します。
IPv4のIPアドレスをチェック
IPv4のIPアドレスのチェックをする正規表現のパターンは次のとおりです。
^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$
IPv4のIPアドレスは、.(ドット)で区切られた0~255の4つの値なので、その範囲の値かどうかをチェックしています。
次のプログラムで確認してみましょう。
[IPv4のアドレスのチェックをするサンプルコード]
import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { // 検索する文字列を用意 String str = "192.168.0.10"; // 正規表現のパターンを作成 Pattern p = Pattern.compile( "^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"); Matcher m = p.matcher(str); System.out.println(m.find()); } }
[実行結果]
true
IPv6のIPアドレスをチェック
IPv6のIPアドレスのチェックをする正規表現のパターンは次のとおりです。
^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*$
この正規表現のパターンは次のリンク先を参考にしたものをJava向けに書き換えて使用しています。
リンク先:helpsystems.com
IPv6のIPアドレスは省略して書けるためパターンが複雑になります。
次のプログラムで確認してみましょう。
[IPv6のアドレスのチェックをするサンプルコード]
import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { // 検索する文字列を用意 String str1 = "1000:2000:3000:4000:5000:6000:7000:abcd"; String str2 = "1:2:3:4:5:6:7:a"; String str3 = "1:2:3::6:7:a"; String str4 = "1:2::a"; // 正規表現のパターンを作成 Pattern p = Pattern.compile("^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|" + "(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|" + "(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|" + "(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|" + "(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|" + "(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|" + "(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|" + "(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*$"); Matcher m = p.matcher(str1); System.out.println(m.find()); m = p.matcher(str2); System.out.println(m.find()); m = p.matcher(str3); System.out.println(m.find()); m = p.matcher(str4); System.out.println(m.find()); } }
[実行結果]
true true true true
メールアドレスのチェック
メールアドレスのチェックをする正規表現のパターンは次のとおりです。
^(([0-9a-zA-Z!#$%&'*+-/=?^_`{}|~]+(.[0-9a-zA-Z!#$%&'*+-/=?^_`{}|~]+)*)|("[^"]*"))@[0-9a-zA-Z!#$%&'*+-/=?^_`{}|~]+(.[0-9a-zA-Z!#$%&'*+-/=?^_`{}|~]+)*$
メールアドレスのルールは複雑なため、正規表現のパターンも分かりにくいものになりが、順に解説していきます。
まず、メールアドレスには英数字の他にも次の記号「! # $ % & ‘ * + – / = ? ^ _ ` { } | ~ .」が使えます。
そのため、英数字の他にも記号を含むパターンを作成しています。エスケープ処理が必要な記号もあるので間違えないように気をつけましょう!
次に、.(ドット)が2つ以上連続してはいけないのでそれもチェックしています。ただし、”(ダブルクォーテーション)で囲んだ場合は.(ドット)が2つ以上連続してもOKなので、それも判定しています。
次のプログラムで確認してみましょう。
[メールアドレスのチェックをするサンプルコード]
import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { // 検索する文字列を用意 String str1 = "Samurai+Engineer.123@gmail.com"; String str2 = "Samurai..Engineer@gmail.com"; String str3 = ""Samurai..Engineer"@gmail.com"; // 正規表現のパターンを作成 Pattern p = Pattern.compile( "^(([0-9a-zA-Z!#$%&'*+-/=?^_`{}|~]+(.[0-9a-zA-Z!#$%&'*+-/=?^_`{}|~]+)*)|("[^"]*"))" + "@[0-9a-zA-Z!#$%&'*+-/=?^_`{}|~]+" + "(.[0-9a-zA-Z!#$%&'*+-/=?^_`{}|~]+)*$"); Matcher m = p.matcher(str1); System.out.println(str1 + " = " + m.find()); m = p.matcher(str2); System.out.println(str2 + " = " + m.find()); m = p.matcher(str3); System.out.println(str3 + " = " + m.find()); } }
[実行結果]
Samurai+Engineer.123@gmail.com = true Samurai..Engineer@gmail.com = false "Samurai..Engineer"@gmail.com = true
URLのチェック
URLのチェックをする正規表現のパターンは次のとおりです。
^https?://[a-z.:/+-#?=&;%~]+$
次のプログラムで確認してみましょう。
[URLのチェックをするサンプルコード]
import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { // 検索する文字列を用意 String str = "http://www.sejuku.net/blog"; // 正規表現のパターンを作成 Pattern p = Pattern.compile("^https?://[a-z.:/+-#?=&;%~]+$"); Matcher m = p.matcher(str); System.out.println(m.find()); } }
[実行結果]
true
まとめ
いかがでしたか?
今回は正規表現の使い方について解説しました。正規表現のパターンを使いこなせば、任意の文字列の検索ができるのようになるのでぜひ覚えてくださいね。
もし、正規表現を使う方法を忘れてしまったらこの記事を確認してください!