正規表現の基本
「決まった形かどうか」を for で調べると 20 行になる
商品コードが「英大文字が続いて、ハイフン、そのあと数字」という形になっているか確かめたいとします。charAt と for で真面目に書くと、位置を数えながら分岐を積む 20 行くらいのコードになります。しかも仕様が少し変わるたびに全部見直しです。
正規表現は、この「形」を 1 本の式で書くための小さな言語です。Java だけの道具ではないので、一度覚えれば他の言語でもほぼそのまま通用します。
かたまりは [ ] と + で表す
[ ] は「この中のどれか 1 文字」という意味です。[A-Z] のように - を挟むと範囲になり、[A-Za-z] のように範囲をいくつでも並べて書けます。+ は「直前のものが 1 文字以上続く」という意味です。
判定には String.matches を使います。
Java
public class Demo {
public static void main(String[] args) {
System.out.println("AB-1234".matches("[A-Z]+-[0-9]+")); // true
System.out.println("Ab-1234".matches("[A-Z]+-[0-9]+")); // false
System.out.println("AB-1234-9".matches("[A-Z]+-[0-9]+")); // false
}
}2 行目が false なのは、[A-Z] に小文字が入っていないからです。3 行目が false なのは、matches が 文字列全体 の一致を見るからです。前半だけ合っていても通りません。一部に含まれているかを調べたいだけなら contains の方が手軽です。
式の中の - や @ のような文字は、そのまま書けばその文字自身を表します。区切りに使う記号は素直に書いて構いません。
. は「なんでも 1 文字」なので、そのままでは使えない
やっかいなのはドットです。正規表現の . は「任意の 1 文字」という意味なので、ドットそのものを表したいときは打ち消す必要があります。困るのは、打ち消し忘れても動いてしまうことです。
Java
System.out.println("1.20".matches("[0-9]+.[0-9]+")); // true
System.out.println("1x20".matches("[0-9]+.[0-9]+")); // true
System.out.println("1x20".matches("[0-9]+\\.[0-9]+")); // false1 行目だけ見ると正しく動いているように見えますが、2 行目でドットのつもりが x まで通っています。3 行目のように \\. と書いて初めて「ドットという文字そのもの」になります。
\ が 2 つ並ぶのは Java 特有の事情です。Java の文字列リテラル自体が \ を特別扱いするので、二重に書く必要があります。
Java
String ok = "\\."; // 文字列としては \. の 2 文字、正規表現は「文字としてのドット」
String ng = "\."; // コンパイルエラー現場のメールアドレス検証は、規格どおりに書こうとすると手に負えない長さになります。形式はざっくり確かめて、本当に届くかどうかは確認メールを送って判断する、というのが実際のやり方です。
課題では、文字列全体が決まった形になっているかを matches で判定します。かたまりを [ ] と + で表し、区切りの記号はそのまま、ドットだけは打ち消す。この 3 点を組み合わせて式を作ってみてください。
要件
String.matchesを使って正規表現で完全一致を判定すること- 正規表現は
[A-Za-z0-9]+@[A-Za-z0-9]+\.[A-Za-z0-9]+の形式で、@の前後とドットの前後にそれぞれ 1 文字以上の英数字があることを保証すること - ドット
.は\\.のように Java 文字列内ではバックスラッシュ 2 つでエスケープすること
入出力例
isEmail("test@example.com") → true
isEmail("a@b.c") → true
isEmail("invalid") → false
isEmail("@example.com") → false
isEmail("") → false
isEmail("test@examplecom") → false
isEmail("test@.com") → false