Java 正規表現

Javaの正規表現を使用して有効なメールアドレスを確認する

2022年3月22日

メールアドレス形式の扱いはサービス単位で異なり、定まっていないので、メールアドレスの妥当性を判定する時に正規表現を使うことが多くなると思います。

基本的にはRFC5321かRFC5322、次点でRFC822に準拠したフォーマットが妥当だとは思いますが、すでに取得されているアドレスが存在するため表記はサービス毎に見直し設定していく必要があります。

単純表現

現在多くのサービスでは、「+_.-」の記号を使用したり、「input type="email"」の形式で入力を制御しているものを見かけます。

「input type="email"」とおまけでAndroidで使われている形式。

import java.util.Scanner;
public class ValidatingEmail { 
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("Enter your Email: ");
        String phone = sc.next;
        String regex = "^[a-zA-Z0-9+_.-]+@[a-zA-Z0-9.-]+$";
        // RFC5321に近いinput type="email"を使う場合↓
        // "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$"
        // Androidで使われるメールアドレス判定↓
        // "[a-zA-Z0-9\+\.\_\%\-\+]{1,256}\@[a-zA-Z0-9][a-zA-Z0-9\-]{0,64}(\.[a-zA-Z0-9][a-zA-Z0-9\-]{0,25})+"

        boolean result = phone.matches(regex);
        if(result) {
            System.out.println("Given email-id is valid");
        } else {
            System.out.println("Given email-id is not valid");
        }
    }
}
//出力
Enter your Email:
test!?@gmail.com
Given email-id is not valid

 

「+_.-」の正規表現で簡易記述でよく見られる形式。

public static final Pattern VALID_EMAIL_ADDRESS_REGEX = 
    Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);

public static boolean isEmailValidate(String emailStr) {
        Matcher matcher = VALID_EMAIL_ADDRESS_REGEX.matcher(emailStr);
        return matcher.find();
}

Apache Commons Validator

Apache Commons Validatorのパッケージには、いくつかの標準検証が含まれています。

検証メソッドを提供するEmailValidatorクラスを使用して、RFC822標準に従って電子メールアドレスを検証できます。

https://commons.apache.org/proper/commons-validator/

import org.apache.commons.validator.routines.EmailValidator;

// Java program to validate email in Java
class Main
{
    public static boolean emailValidator(String email)
    {
        // Get an EmailValidator
        EmailValidator validator = EmailValidator.getInstance();

        // Validate specified String containing an email address
        if (!validator.isValid(email)) {
            return false;
        }
        return true;
    }

    public static void main(String[] args)
    {
        String email = "no-reply@techiedelight.com";

        // Validate an email address
        if (emailValidator(email)) {
            System.out.println("The email address " + email + " is valid");
        }
        else {
            System.out.println("The email address " + email + " is invalid");
        }
    }
}

RFCで公開されている正規表現

ガチガチのRFC5322かRFC5321、またはRFC822の正規表現はとても長いので、直して使うのはメンテを考えるとおすすめしません。

RFC822

RFC-822に完全に準拠した電子メールの正規表現は、とても巨大なものです。

Javaで書き直すのは長大すぎるので、RFC822に準拠しているInternetAddressを使う事を検討して下さい。

ユーザーのメールアドレスを入力する際、InternetAddressのコンストラクタに渡すことで検証を行うことができます。

入力値がRFC822に準拠していない場合、例外がスローされます。

public static boolean isValidEmailAddress(String aEmailAddress){
    if (aEmailAddress == null) return false;
    boolean result = true;
    try {
        InternetAddress emailAddr = new InternetAddress(aEmailAddress);
        if (! hasNameAndDomain(aEmailAddress)) {
          result = false;
        }
    } catch (AddressException ex) {
      result = false;
    }
    return result;
}

RFC5322

RFC5322はRFC822の更新版であり、電子メール検証のための正規表現を提供しています。

比較的単純な正規表現で、メールに含まれるすべての文字を許可します。

ただし、パイプ文字(|)とシングルクォート(')は許可すべきではありません。

これらは、クライアントサイトからサーバーに渡されたときにSQLインジェクションのリスクになる可能性があるからです。

//RFC 5322 
//RFC 5322に準拠して簡易表現にした正規の電子メールアドレス
regexp5322_1 = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$";

//RFC 5322 
//電子メール正規表現 RFC 5322公式標準を踏襲型
regexp5322_2 = "(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])";

RFC 5321

RFC 5321はホスト名とIPアドレスの両方に関しての扱いが寛大なため注意が必要です。

Javaの正規表現を使用してRFC 5321に準拠したメールアドレスを確認する
Javaの正規表現を使用してRFC 5321に準拠したメールアドレスを確認する

RFC 5321:Simple Mail Transfer Protocol(SMTP)はメールサーバ間におけるメッセージの転送方式を定めた標準仕様です。 https://tools.ietf.org ...

Gmail用のケース

Gmailにのみ適用される特殊なケースがあります。

それは、メールのローカル部分に+文字の使用を許可する事です。

Gmailドメインの場合、username+something@gmail.comとusername@gmail.comの2つのメールアドレスは同じです。

public static void main(String []args){
    String emailAddress = "username+something@domain.com";
    String regexPattern = "^(?=.{1,64}@)[A-Za-z0-9\\+_-]+(\\.[A-Za-z0-9\\+_-]+)*@"+"[^-][A-Za-z0-9\\+-]+(\\.[A-Za-z0-9\\+-]+)*(\\.[A-Za-z]{2,})$";
    boolean result = emailAddress.matches(regexPattern);
    if(result) {
        System.out.println("Gmail is valid");
    } else {
        System.out.println("Gmail is not valid");
    }
}
//Gmail is valid

最後に

自前のメールアドレスポリシーがある場合は正規表現で実装するしかありませんが、正規表現などを使って独自にメールアドレスパーサーを実装することは、ほとんどの場合あまり良くない考えです。

長く運用すると、詳細を正しく理解するの事が難しくなり、間違いを犯す可能性が高くなるからです。

さらに多くの場合、実運用に入るまで記述の間違いだけでなく、運用方針の間違いに気づくことがないのも問題です。

そういった運用経験から、海外の識者は昔Javaの電子メールの検証を、RFC822に準拠しているInternetAddressに基づくものを推していました。現代だと許容幅が広過ぎるかもしれません。

おまけ

正規表現チェッカー

https://www.regexplanet.com/advanced/java/index.html

このサイトは対応言語が多く、インプットで使えるワードが多いためテストがし易く非常に検証しやすいです。

また、入力できる正規表現の文字数も多く、他のチェッカーサイトだと桁が溢れるものも検証できるのが優れものです。

  • この記事を書いた人

朝倉卍丸

シングルモルトスコッチなどのお土産を持ってきた人を助けるのが好きです。サービスの分割が重要ですが、まあ昔ながらの方法でやりたいこともありますよね。

よく読まれている記事

条件の0=0は全てが正であるを意味するSQL 1

SQLの条件に0=0のような記述を見かけます。 変わった書き方の条件ですが、これは「全てが正である」事を意味しており、結合条件の場合はCROSS JOINと同じです。 下記の例で言えば、結合するsub ...

DISTINCTを使わないで重複排除を考えるSQL 2

SQLのDISTINCTはEXISTSとかGROUP BYでなんとかする事もできます。 DISTINCTは暗黙的なソートがされますが、何のDBを使うにせよ過去のバージョンならともかく、最近のバージョン ...

RFC 5322に準拠させた正規表現言語別 3

RFC5322で定義されている正規表現を、各言語の正規表現に変化させた形になります。 完全な電子メール正規表現は存在しないので、結局のところ何かの公式基準に従っていたとしても、自分が携わるサービスのル ...

-Java, 正規表現