正则表达式详解与 Java 实践-预定义字符类/重复类/反义类/分组/零宽断言

正则表达式详解与 Java 实践

在一次面试中,面试官提出了以下关于正则表达式的问题。本文将逐一解答,并结合一个具体的 Java 场景------从文本中提取并验证电子邮件地址------进行代码实践,同时针对"零宽断言"和复杂模式的疑问进行详细说明。

1. 什么是正则表达式?

正则表达式(Regular Expression,简称 regex)是一种用于匹配、查找和操作文本的强大工具。它通过定义特定的模式(pattern),来描述需要匹配的字符串规则。
场景实践 :假设我们需要从一段文本中提取电子邮件地址,正则表达式可以帮助我们定义邮箱的模式,例如 [email protected]

2. 简述正则表达式的字符类

字符类(Character Class)用于匹配一组特定字符中的任意一个,用方括号 [] 表示。例如,[abc] 表示匹配 abc 中的一个字符。
场景实践 :在邮箱中,用户名可能包含字母、数字或下划线,我们可以用 [a-zA-Z0-9_] 来匹配这些字符。

3. 正则表达式有哪些预定义的字符类?

预定义字符类是正则表达式中内置的简写形式,用于表示常见的字符集合,例如:

  • \d:匹配任意数字 [0-9]
  • \w:匹配任意字母、数字或下划线 [a-zA-Z0-9_]
  • \s:匹配任意空白字符(空格、制表符等)
  • .:匹配除换行符外的任意字符
    场景实践 :在邮箱模式中,\w 可以用来匹配用户名中的字符,例如 [\w.-] 表示用户名可以包含字母、数字、下划线、点或横杠。

4. 正则表达式有哪些重复类?

重复类(Quantifiers)用于指定字符或模式的重复次数,包括:

  • *:0 次或多次
  • +:1 次或多次
  • ?:0 次或 1 次
  • {n}:恰好 n 次
  • {n,}:至少 n 次
  • {n,m}:n 到 m 次
    场景实践 :邮箱用户名可能包含多个字符,我们用 \w+ 表示用户名至少包含一个字母、数字或下划线。

5. 正则表达式有哪些反义类?

反义类(Negated Character Class)表示不匹配某些字符,通常用 ^ 在字符类中表示,例如:

  • [^abc]:匹配除 abc 外的任意字符
  • \D:匹配非数字字符 [^\d]
  • \W:匹配非字母、数字或下划线的字符 [^\w]
  • \S:匹配非空白字符 [^\s]
    场景实践 :在邮箱验证中,我们可能需要确保域名部分不包含空白字符,可以用 \S

6. 正则表达式分组是什么?

分组(Grouping)使用括号 () 将正则表达式的一部分组合起来,可以:

  • 捕获匹配的内容供后续使用(通过组编号或命名组)
  • 对模式应用量词
    场景实践 :在邮箱中,我们可以用 (\w+) 分组捕获用户名部分,之后可以通过组号提取它。

7. 正则表达式零宽断言是什么?

零宽断言(Zero-width Assertion)是一种不占用字符宽度的匹配条件,用于指定匹配位置的上下文。它像是站在字符串中的某个点上,向前或向后"偷看"一眼,判断是否符合要求,但不会把"偷看"的内容算进匹配结果。包括:

  • (?=...):正向肯定预查,检查后面是否符合某个模式
  • (?!...):正向否定预查,检查后面不符合某个模式
  • (?<=...):反向肯定预查,检查前面是否符合某个模式
  • (?<!...):反向否定预查,检查前面不符合某个模式

通俗例子 :假设你在一条街上找房子,要求房子右边必须有公园(但公园不算在房子范围内),这就是正向肯定预查 (?=公园)

  • 输入:房子A公园 房子B商场 房子C公园
  • 匹配:房子A房子C,因为它们右边有公园,但"公园"不包含在结果中。

场景实践 :在邮箱提取中,我们用 (?=\.com$) 确保匹配的邮箱以 .com 结尾。例如:

  • 输入:[email protected] [email protected]
  • 模式:@(\w+)\.(\w+)(?=\.com$)
  • 结果:只匹配 domain,因为它后面是 .com,而 xyz 后面是 .org,不满足条件。
    为什么叫"零宽"? 因为它只检查条件,不消耗字符。比如在 [email protected] 中,(?=\.com$) 检查 @domain 后的位置,确认后面是 .com,但 .com 不会被包括在最终匹配结果中。

8. 正则表达式的贪婪与懒惰是什么?

正则表达式的匹配默认是贪婪模式(Greedy) ,即尽可能多地匹配字符;通过在量词后加 ? 可以变为懒惰模式(Lazy),即尽可能少地匹配。

  • 贪婪:.* 会匹配整个字符串
  • 懒惰:.*? 只匹配到满足条件的最短部分
    场景实践 :在提取多个邮箱时,贪婪模式可能匹配过多的内容,而懒惰模式 .*? 可以更精确地定位每个邮箱。

Java 代码实践:提取并验证电子邮件地址

以下是一个 Java 示例,展示如何使用正则表达式从文本中提取电子邮件地址,并验证其格式,同时对比简单模式和复杂模式的差异。

java 复制代码
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class EmailExtractor {
    public static void main(String[] args) {
        // 示例文本
        String text = "联系方式: [email protected], [email protected], [email protected]";

        // 简单模式:只用 \w+
        String simplePattern = "\\w+@\\w+\\.\\w{2,4}";
        System.out.println("简单模式匹配:");
        matchEmails(text, simplePattern);

        // 复杂模式:支持 . 和 -,并用零宽断言限制 .com
        String complexPattern = "(\\w+([.-]?\\w+)*)@(\\w+([.-]?\\w+)*\\.\\w{2,4})(?=\\.com$)";
        System.out.println("\n复杂模式匹配(仅限 .com):");
        matchEmails(text, complexPattern);
    }

    private static void matchEmails(String text, String pattern) {
        Pattern p = Pattern.compile(pattern);
        Matcher m = p.matcher(text);
        while (m.find()) {
            String email = m.group(0); // 完整邮箱
            String username = m.group(1); // 用户名部分
            String domain = m.group(3); // 域名部分
            System.out.printf("邮箱: %s, 用户名: %s, 域名: %s%n", email, username, domain);
        }
    }
}

代码解析

  1. 简单模式 \w+@ 的局限性

    • 只适合基本格式(如 [email protected])。
    • 对于带 .- 的用户名(如 alice.smith-jr),会失败。
  2. 复杂模式 (\w+([.-]?\w+)*)@(\w+([.-]?\\w+)*\.\\w{2,4})(?=\\.com$)

    • 用户名部分 (\w+([.-]?\w+)*)
      • \w+:匹配至少一个字母、数字或下划线(如 alice)。
      • [.-]?\w+:匹配可选的 .-,后跟字母、数字或下划线(如 .smith-jr)。
      • *:允许出现多次(如 alice.smith-jr)。
    • 域名部分 (\w+([.-]?\\w+)*\.\\w{2,4})
      • 类似用户名,支持复杂域名(如 sub.domain.com)。
      • \.\\w{2,4}:匹配顶级域名(如 .com),长度 2-4 个字符。
    • 零宽断言 (?=\.com$) :确保邮箱以 .com 结尾,不匹配 .org 等。
  3. 为什么不用简单的 \w+

    对于 [email protected]\w+ 确实够用。但真实邮箱可能包含 .-(如 [email protected]),简单模式会漏掉这些情况。复杂模式更灵活,能覆盖更多场景。

输出示例

java 复制代码
简单模式匹配:
邮箱: [email protected], 用户名: alice123, 域名: domain.com
邮箱: [email protected], 用户名: alice, 域名: xyz.com
邮箱: [email protected], 用户名: bob, 域名: xyz.org

复杂模式匹配(仅限 .com):
邮箱: [email protected], 用户名: alice123, 域名: domain.com

总结

正则表达式是处理文本的利器,掌握其字符类、重复类、反义类、分组、零宽断言以及贪婪/懒惰模式,可以应对复杂的匹配需求。通过 Java 的 PatternMatcher,我们可以轻松实现文本提取和验证功能。零宽断言为我们提供了位置检查的灵活性,而复杂模式则确保了更广泛的适用性。

相关推荐
冷琅辞4 小时前
Elixir语言的云计算
开发语言·后端·golang
Asthenia04125 小时前
编译原理基础:LL(1) 文法与 LL(1) 分析法
后端
Asthenia04126 小时前
编译原理基础:FIRST 集合与 FOLLOW 集合的构造与差异
后端
Asthenia04126 小时前
编译原理基础:FOLLOW 集合与 LL(1) 文法条件
后端
Asthenia04126 小时前
编译原理基础:FIRST 集合与提取公共左因子
后端
欧宸雅7 小时前
Clojure语言的持续集成
开发语言·后端·golang
Bruce_Liuxiaowei7 小时前
基于Flask的DeepSeek~学术研究领域智能辅助系统设计与实现
后端·python·flask·deepseek
Asthenia04127 小时前
面试官问:你谈谈网络协议栈是什么?你觉得Java工程师需要了解哪些部分?
后端
穿林鸟8 小时前
Spring Boot项目信创国产化适配指南
java·spring boot·后端