1. 概述

本教程将系统介绍如何使用正则表达式在Java中进行邮箱地址验证。我们将从基础到高级,逐步拆解不同验证场景的实现方案。

2. Java中的邮箱验证基础

几乎所有涉及用户注册的应用都需要邮箱验证。邮箱地址由三部分组成:本地部分、@符号和域名。例如username@domain.com中:

  • 本地部分 = username
  • @ = @
  • 域名部分 = domain.com

通过字符串操作手动验证邮箱需要处理字符类型、长度等细节,非常繁琐。但使用正则表达式可以大幅简化验证过程。正则表达式本质上是用来匹配特定模式的字符序列,后续章节将展示多种基于正则的验证方案。

3. 简单正则验证

最基础的邮箱验证正则表达式为:^(.+)@(\\S+)$

它仅检查邮箱中是否存在@符号:

  • 存在@则返回true
  • 不存在则返回false

该表达式不会检查本地部分和域名的具体格式。例如:

  • test@example.com → 通过验证
  • username#domain.com → 验证失败(缺少@)

定义辅助方法进行模式匹配:

public static boolean patternMatches(String emailAddress, String regexPattern) {
    return Pattern.compile(regexPattern)
      .matcher(emailAddress)
      .matches();
}

测试用例:

@Test
public void testUsingSimpleRegex() {
    String emailAddress = "test@example.com";
    String regexPattern = "^(.+)@(\\S+)$";
    assertTrue(EmailValidation.patternMatches(emailAddress, regexPattern));
}

4. 严格正则验证

更严格的正则表达式会同时检查本地部分和域名格式: ^(?=.{1,64}@)[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)*@[^-][A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$

本地部分限制:

  • 允许数字0-9
  • 允许大小写字母a-z
  • 允许特殊字符 _-.
  • 禁止.开头或结尾
  • 禁止连续.出现
  • 最大长度64字符

域名部分限制:

  • 允许数字0-9
  • 允许大小写字母a-z
  • 禁止-.开头/结尾
  • 禁止连续.出现

测试用例:

@Test
public void testUsingStrictRegex() {
    String emailAddress = "test.user@example.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,})$";
    assertTrue(EmailValidation.patternMatches(emailAddress, regexPattern));
}

有效邮箱示例:

  • test@example.com
  • test.user@sub.domain.com
  • test_user123@example.com
  • test-user@example.co.uk
  • 123test@example.com

无效邮箱示例:

  • test@.com(域名以点开头)
  • test@domain..com(连续点)
  • test@domain.com.(域名以点结尾)
  • test@-domain.com(域名以连字符开头)

5. 支持Unicode字符的正则验证

前述正则仅适用于英文邮箱,对非拉丁字符(如中文)无效。支持Unicode的正则表达式: ^(?=.{1,64}@)[\\p{L}0-9_-]+(\\.[\\p{L}0-9_-]+)*@[^-][\\p{L}0-9-]+(\\.[\\p{L}0-9-]+)*(\\.[\\p{L}]{2,})$

关键改动:将A-Za-z替换为\\p{L}以支持Unicode字符。

测试用例:

@Test
public void testUsingUnicodeRegex() {
    String emailAddress = "用户名@领域.电脑";
    String regexPattern = "^(?=.{1,64}@)[\\p{L}0-9_-]+(\\.[\\p{L}0-9_-]+)*@" 
        + "[^-][\\p{L}0-9-]+(\\.[\\p{L}0-9-]+)*(\\.[\\p{L}]{2,})$";
    assertTrue(EmailValidation.patternMatches(emailAddress, regexPattern));
}

6. 基于RFC 5322标准的正则验证

RFC 5322(更新版RFC 822)提供了官方邮箱验证正则: ^[a-zA-Z0-9_!#$%&'*+/=?{|}~^.-]+@[a-zA-Z0-9.-]+$`

该正则允许邮箱中包含大多数特殊字符,但出于安全考虑,禁止使用管道符(|)和单引号(')(可能引发SQL注入风险)。

测试用例:

@Test
public void testUsingRFC5322Regex() {
    String emailAddress = "test!#$%&'*+/=?`{|}~^.-@example.com";
    String regexPattern = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$";
    assertTrue(EmailValidation.patternMatches(emailAddress, regexPattern));
}

7. 顶级域名验证正则

专门验证顶级域名(TLD)的正则表达式: ^[\\w!#$%&'*+/=?{|}^-]+(?:\.[\w!#$%&'*+/=?`{|}^-]+)*@(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,6}$`

核心规则:

  • 邮箱中必须包含至少一个点
  • 顶级域名长度为2-6个字符

测试用例:

@Test
public void testTopLevelDomain() {
    String emailAddress = "test@example.co.uk";
    String regexPattern = "^[\\w!#$%&'*+/=?`{|}~^-]+(?:\\.[\\w!#$%&'*+/=?`{|}~^-]+)*" 
        + "@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$";
    assertTrue(EmailValidation.patternMatches(emailAddress, regexPattern));
}

8. 限制连续/首尾点的正则验证

禁止邮箱中出现连续点、首尾点的正则表达式: ^[a-zA-Z0-9_!#$%&'*+/=?{|}^-]+(?:\.[a-zA-Z0-9_!#$%&'*+/=?`{|}^-]+)*@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$`

核心规则:

  • 允许多个点存在
  • 禁止连续点出现
  • 禁止点出现在本地部分或域名部分的首尾

测试用例:

@Test
public void testRestrictDots() {
    String emailAddress = "test.user@example.com";
    String regexPattern = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^-]+(?:\\.[a-zA-Z0-9_!#$%&'*+/=?`{|}~^-]+)*@" 
        + "[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$";
    assertTrue(EmailValidation.patternMatches(emailAddress, regexPattern));
}

9. OWASP推荐验证正则

OWASP(开放式Web应用程序安全项目)推荐的邮箱验证正则: ^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$

该正则覆盖了标准邮箱结构的大多数验证场景。

测试用例:

@Test
public void testOwaspValidation() {
    String emailAddress = "test+alias@example.com";
    String regexPattern = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
    assertTrue(EmailValidation.patternMatches(emailAddress, regexPattern));
}

10. Gmail邮箱特殊处理

Gmail邮箱存在特殊规则:

  • 允许在本地部分使用+符号
  • test@gmail.comtest+alias@gmail.com指向同一邮箱
  • test.user@gmail.com等同于testuser@gmail.com

适配Gmail的正则表达式: ^(?=.{1,64}@)[A-Za-z0-9\\+_-]+(\\.[A-Za-z0-9\\+_-]+)*@[^-][A-Za-z0-9\\+-]+(\\.[A-Za-z0-9\\+-]+)*(\\.[A-Za-z]{2,})$

测试用例:

@Test
public void testGmailSpecialCase() {
    String emailAddress = "test+alias@gmail.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,})$";
    assertTrue(EmailValidation.patternMatches(emailAddress, regexPattern));
}

11. 使用Apache Commons Validator

Apache Commons Validator提供现成的邮箱验证工具,基于RFC 822标准实现。该工具结合自定义代码和正则表达式,支持特殊字符和Unicode。

添加Maven依赖:

<dependency>
    <groupId>commons-validator</groupId>
    <artifactId>commons-validator</artifactId>
    <version>1.8</version>
</dependency>

验证示例:

@Test
public void testUsingEmailValidator() {
    String emailAddress = "test@example.com";
    assertTrue(EmailValidator.getInstance()
      .isValid(emailAddress));
}

12. 如何选择合适的正则表达式

选择验证方案取决于具体需求:

  • 基础验证:仅需检查@符号 → 使用第3节简单正则
  • 严格验证:需完整格式校验 → 推荐第6节RFC 5322正则
  • 国际化支持:需处理Unicode字符 → 使用第5节Unicode正则
  • 安全场景:需防范注入风险 → 避免包含|'的正则

13. 总结

本文系统介绍了Java中使用正则表达式验证邮箱的多种方案,从基础到高级,涵盖不同场景需求。关键要点:

  • 正则表达式是邮箱验证的高效工具
  • 根据业务需求选择严格程度
  • 特殊场景(如Gmail)需单独处理
  • 生产环境可考虑Apache Commons Validator

完整代码示例可在GitHub仓库获取。


原始标题:Email Validation in Java | Baeldung