Javaの学習を進めていく中で「正規表現」という言葉を耳にすると思います。
初めて名前を聞いた方は「正規表現っていったい何だろう?」と思うかもしれません。
そんな方のためにここでは、
- 正規表現とは
- メタキャラクタの意味と使い方
- Javaの正規表現とは
- エスケープ文字と記述法
- 代表的な正規表現
- 一致する文字列のチェック方法
- 一致する文字の抽出方法
など、正規表現の基本的な内容と使い方をわかりやすくご紹介していきます。
Java初心者の方のために、代表的な正規表現のサンプルもご用意していますので、ぜひ活用してくださいね!
正規表現は機械に文字列の処理を行わせるために必要な道具
正規表現とは、機械に文字列の処理を行わせるために必要な道具のようなものです。
具体的には、
- 文字列を探し出す
- 特定の処理を加える
などの処理をするために使われる表現方法になっています。
正規表現では、以下の2つの文字列を組み合わせて文字列の検索ができます。
- 通常の文字(a〜zなど)
- 特殊な意味を持つ記号(.(ピリオド)や^(キャレット)など)で表現するメタキャラクタ
- 正規表現は機械に文字列の処理を行わせるための道具
- 通常の文字と特殊な意味を持つ文字を組み合わせて使用する
代表的なメタキャラクタまとめ
メタキャラクタそれぞれが持つ意味と使い方をまとめていきます。
メタキャラクタを使った文字列の具体的な検索方法は、後ほどご紹介していきます。
記号 | 意味 | 使い方 | 一致する文字列 |
. | 任意の1文字を意味します | .回 | 0回
一回 |
^ | 行の先頭を意味します | ^さようなら | さようなら先生
さようなら皆さん |
$ | 行末を意味します | $さようなら | 先生さようなら
皆さんさようなら |
+ | 直前にある文字の1回以上の繰り返しを意味します | app+le | apple
apppppple |
? | 直前の文字の0回または1回の繰り返しを意味します | apple? | apple
appl |
* | 直前の文字の0回以上の繰り返しを意味します | apple* | apple
appleeeeeee |
| | 区切られた文字列のうちのいずれかを意味します | apple|orange | apple
orange |
[ ] | くくられた文字の中のいずれか一つを意味します | 私は[男女]の子です | 私は男の子です
私は女の子です |
( ) | 複数の文字列をひとまとめしたものを表現します | (Ha)+ | Ha
HaHaHa |
[^] | 任意の1文字と不一致であること意味します | ap[^p]le | aplle
apole |
メタキャラクタを文字として記述する方法
メタキャラクタのように、文字本来の意味とは別の意味で解釈できる文字のことを「エスケープ文字」と呼びます。
「.」や「?」を検索したい場合も当然ながら出てきますが、普通に記述をしてもエスケープ文字として認識されてしまいます。
メタキャラクタとして使っている文字と、検索対象として使われる文字を区別するために「\」を使って表現します。
使い方はいたって簡単で、メタキャラクタではなく、通常の文字として使用したい文字の前に置くだけです。
例えば、「\.」と記述をすると「任意の1文字」ではなく、「.」という文字の指定になります。また、「\」は「\」自身の意味の打ち消しにも使えるので、「\\」とした場合は「\」という文字を指定したことになります。
なお、メタキャラクタの中には「\」で意味を打ち消さなくても、置かれた場所によってメタキャラクタの意味を失うものがあります。例えば、「^」は検索する文字列の先頭に置かなければ意味を持たないため「a^」と記述した場合、「^」は文字として扱われます。
同様に、「$」も行末に置かなければメタキャラクタとしての意味を持ちません。
- 「\」はメタキャラクタの意味を打ち消す
- メタキャラクタの意味を打ち消したいときは「/」を文字の前に置く
- 「\」は「\」自身の意味も打ち消せる
Javaの正規表現
原理は理解できたので、次は具体的な記述の仕方を教えてください。
分かりました。ここでは実際の記述例を見ながらどのような値が返ってくるのかを見てみることにします。
実際のプログラミングの中で利用する場合の、正規表現の記述例を説明していきます。
public class Main { public static void main(String[] args) { // 判定する文字列 String str = "私はJavaの勉強をしている"; // 正規表現で「Java」が含まれているかを判定 if(str.matches(".*Java.* ")){ System.out.println(str + "には「Java」が含まれています"); }else{ System.out.println(str + "には「Java」が含まれていません"); } } }
この記述例は、strという文字列の中に「Java」という文字が含まれているかを
検索し、判定しています。
if(str.matches(".*Java.* ")){
matchesメソッドの引数に渡している「”.*Java.* “」が正規表現です。
ちなみにmatchesメソッドはMatcherクラスのメソッドで、Javaで文字列検索をするときによく使用されます。
正規表現で指定した文字列を検索し、一致した場合はtrueを返し、一致しなかった場合はfalseを返します。
指定した文字列とメタキャラクタは「””(ダブルクォーテーション)」で囲みます。
「Java」の左右にある「.*」がメタキャラクタで、「0文字以上の任意の文字列」という意味を持っています。
したがって、
- 彼女はJavaの天才だ
- Javaは難しい
- Java
のいずれでも、「str(文字列)にはJavaが含まれています」という結果になります。
代表的な正規表現まとめ
ここでは、正規表現でよく使われる代表的なものをまとめていきます。
使い方は後ほどご紹介していきますね。
記号 | 意味 |
^[a-z]+$ | 小文字26英字 |
^[A-Z]+$ | 大文字26英字 |
^[A-Za-z]+$ | 大文字小文字26英字 |
^[0-9]*$ | 数字 |
^[A-Za-z0-9]+$ | 英数字 |
^0[789]0-\d{4}-\d{4}$ | 電話番号(携帯番号) |
^[\w!#%&’/=~`\*\+\?\{\}\^\$\-\|]+(\.[\w!#%&’/=~`\*\+\?\{\}\^\$\-\|]+)*@[\w!#%&’/=~`\*\+\?\{\}\^\$\-\|]+(\.[\w!#%&’/=~`\*\+\?\{\}\^\$\-\|]+)*$ | メールアドレス |
^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$ | ドメイン名 |
^(http|https)://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$ | URL |
^\d{3}-\d{4}$ | 郵便番号 |
^\d{4}-\d\d-\d\d$ | 日付(YYYY-MM-DD) |
正規表現の使い方まとめ
正規表現でよく使われる、以下のプログラムの書き方をまとめてご紹介します。
- 電話番号
- メールアドレス
- 日付
- 郵便番号
これからご紹介するサンプルをそのまま利用すれば、文字列のチェックや抽出ができますので参考にしてみてくださいね。
電話番号のチェック
電話番号(携帯番号)のチェックをする正規表現のプログラムの書き方は、以下のようになります。
public class Main { public static void main(String[] args) { // 判定する文字列 String str = "090-1234-5678"; // 正規表現で電話番号の形式になっているか判定 if(str.matches("^0[789]0-\d{4}-\d{4}$")){ System.out.println(str + "は携帯電話の番号です"); }else{ System.out.println(str + "は携帯電話の番号ではありません"); } } }
if(str.matches("^0[789]0-\d{4}-\d{4}$")){
「\d」は数字([0-9])を意味しています。
「0[789]0」の部分で「090」「080」「070」のどれかであることをチェックしています。
なお、「0[789]0」の部分を「0[0-9]{2}」などに書き換えることで、携帯番号以外の番号もチェックすることもできますよ。
「\d{4}」は4桁の数字であることを意味しています。
したがって、このプログラムの「090-1234-5678」は条件と一致しており、電話番号であると判定します。
「090-123-4567」のように、桁が足りていない場合は電話番号でないと判定されますよ。
メールアドレスのチェック
public class Main { public static void main(String[] args) { // 判定する文字列 String str = "java-regex@example.com"; // 正規表現でメールアドレスの形式になっているか判定 if(str.matches("^[\w!#%&'/=~`\*\+\?\{\}\^\$\-\|]+(\.[\w!#%&'/=~`\*\+\?\{\}\^\$\-\|]+)*@[\w!#%&'/=~`\*\+\?\{\}\^\$\-\|]+(\.[\w!#%&'/=~`\*\+\?\{\}\^\$\-\|]+)*$")){ System.out.println(str + "はメールアドレスです"); }else{ System.out.println(str + "はメールアドレスではありません"); } } }
メールアドレスを判定する正規表現は非常に複雑になっているため、「@」の前半と後半にわけて簡単に説明をしていきます。
まず「\w」は、単語構成文字([a-zA-Z_0-9])を意味しています。
^[\w!#%&'/=~`\*\+\?\{\}\^\$\-\|]+
この部分で、先頭文字が以下の2種類で構成された文字列であることを示しています。
- 英数字
- ! #%&’/=~`*+?\^$-|
「\*\+\?\{\}\^\$\-\|」の部分が、エスケープ文字を考慮した記述法になっていることがわかります。
「+」のメタキャラクタで、直前の文字の1回以上繰り返しです。
したがって、「a1b2c3d!%」や「&」でも条件に一致します。
(\.[\w!#%&'/=~`\*\+\?\{\}\^\$\-\|]+)
ここでは、はじめに「.」を指定し、以降は英数字と指定した記号が含まれているかを確認しています。
「.efgh1234」や「.?」といった文字列が、上記の条件に一致しますね。
「*@」の部分は、直前の文字の0回以上の繰り返しです。
^[\w!#%&'/=~`\*\+\?\{\}\^\$\-\|]+(\.[\w!#%&'/=~`\*\+\?\{\}\^\$\-\|]+)*@
したがって、「a.&@」「a@」「ab5.6&@」などの文字列が、上記の条件に一致します。
ここまでがわかれば「@」の後は、英数字か指定した記号の文字列であることを判定しているのがわかるでしょう。
日付のチェック
日付のチェックをする正規表現のプログラムの書き方は、以下のようになります。
public class Main { public static void main(String[] args) { // 判定する文字列 String str = "1999-01-01"; // 正規表現で「1999」年生まれであるか判定 if(str.matches("^1999-\d\d-\d\d$")){ System.out.println(str + "は1999年生まれです"); }else{ System.out.println(str + "は1999年生まれではありません"); } } }
ここでは正規表現を少し変えて、1999年生まれであるかどうかを判定する処理にしてみました。
基本的な考え方は電話番号と同じになっています。
日付は、うるう年などがあり正規表現で厳密に判定をするのは難しいです。
よりしっかり判定を行いたいのであれば、SimpleDateFormatクラスを使うのがオススメされています。
また、「^\d{4}-\d\d-\d\d$」ですと「0000-00-00」でも一致することになるので、適宜修正を加えるとより正確な日付を確認することができますよ。
ここでは割愛させていただきましが、興味がある方は調べてみるといいでしょう。
郵便番号のみを抽出
最後に、複数の文字列の中から、郵便番号だけを抽出する正規表現のプログラムの書き方をご紹介します。
public class Main { public static void main(String[] args) { // 判定する文字列 String str = "田中太郎 東京都新宿区 160-0000 090-1234-5678"; // 正規表現で郵便番号の形式の文字列があるか判定 Pattern p = Pattern.compile("^\d{3}-\d{4}$"); Matcher m = p.matcher(str); if(m.find()){ System.out.println("郵便番号は " + m.group()); } } }
このプログラムでは、Matcherクラスで定義されているfindメソッドを使って、郵便番号の文字列と一致しているかをまず確認しています。
そして同じく、Matcherクラスで定義されているgroupメソッドを使って文字列を抽出しています。
このプログラムの結果は、
郵便番号は 160-0000
となります。
以上が、一致した文字列の抽出方法でした。
Javaの正規表現まとめ
Javaの正規表現の内容や書き方をご紹介していきました。
正規表現が使えるようになると、文字列の検索ができたり、指定した文字列の抽出にも応用ができます。
一度で全部覚える必要はないので、正規表現を使う場面がありましたらこの記事をぜひ参考にしてみてくださいね。