欢迎光临
我们一直在努力

【正则表达式详解|Java】从0学习实战够用

目录

Java 正则前置须知

Java 正则常用语法分类详解

分类 1:基础元字符(匹配单个字符)

分类 2:量词(控制匹配次数)

关键区别:贪婪 vs 非贪婪(实战重点)

分类 3:字符类(匹配指定范围的字符)

示例(验证是否为小写字母)

分类 4:边界匹配器(匹配位置,非字符)

关键示例(完整验证手机号,核心场景)

分类 5:捕获组与非捕获组(提取 / 复用内容)

1. 捕获组(常用)

示例(提取座机号的区号和号码)

2. 非捕获组(仅匹配,不提取)


学习Java爬虫时顺手补缺笔记。正则表达式学了不用经常忘记并且大部分工作可以直接ai,因此这里要求够用,能看到即可。

Java 正则前置须知

  • 核心类:Java 中操作正则依赖 java.util.regex 包下的两个类:
    • Pattern:编译正则表达式(Pattern.compile(regex)),生成不可变的正则对象。
    • Matcher:执行匹配操作,通过 pattern.matcher(input) 获取,提供 find()、group() 等方法。
  • 关键转义:Java 字符串中 \\ 是转义字符,因此正则中的 \\ 必须写成 \\\\(双重转义),例如:
    • 原生正则 \\d(匹配数字),在 Java 中要写为 \\\\d。
    • 原生正则 \\"(匹配双引号),在 Java 中要写为 \\\\\\"(先转义\\,再转义")。
  • 匹配流程:编译正则 → 获取匹配器 → 执行匹配 → 提取结果(对应你之前的代码逻辑)。
  • Java 正则常用语法分类详解

    分类 1:基础元字符(匹配单个字符)

    元字符是正则的基础,用于匹配单个特定字符或字符类型,以下是最常用的元字符,标注「原生正则」和「Java 写法」的区别。

    原生正则Java 写法含义说明适用示例
    . . 匹配除「换行符 \\n」外的任意单个字符 匹配 a、1、@、/ 等
    \\d \\\\d 匹配单个数字(0-9),等价于 [0-9] 匹配手机号、身份证号中的数字
    \\D \\\\D 匹配单个非数字字符,等价于 [^0-9] 提取字符串中的非数字部分
    \\w \\\\w 匹配单个「单词字符」(字母、数字、下划线),等价于 [a-zA-Z0-9_] 匹配变量名、用户名
    \\W \\\\W 匹配单个「非单词字符」,等价于 [^a-zA-Z0-9_] 匹配标点符号、特殊符号
    \\s \\\\s 匹配单个空白字符(空格、制表符 \\t、换行符 \\n 等) 去除字符串中的多余空白
    \\S \\\\S 匹配单个非空白字符 提取字符串中的有效内容(排除空白)
    \\\\ \\\\\\\\ 匹配反斜杠 \\ 本身(特殊字符需要转义) 匹配文件路径中的 \\
    \\. \\\\. 匹配小数点 . 本身(. 是元字符,需转义) 匹配邮箱、URL 中的小数点

    示例代码(匹配单个数字)

    String regex = "\\\\d"; // Java写法,对应原生\\d
    String input = "abc123def";
    Pattern pattern = Pattern.compile(regex);
    Matcher matcher = pattern.matcher(input);
    while (matcher.find()) {
    System.out.println("匹配到数字:" + matcher.group()); // 输出:1、2、3
    }

    分类 2:量词(控制匹配次数)

    量词用于指定「前面的字符 / 元字符 / 捕获组」的匹配次数,分为「贪婪匹配」(默认,尽可能多匹配)和「非贪婪匹配」(加 ?,尽可能少匹配),是正则的核心常用语法。

    语法含义说明贪婪 / 非贪婪示例(Java 写法)
    * 匹配前面的内容 0 次或多次 贪婪 \\\\d*:匹配 0 个或多个数字(可空)
    + 匹配前面的内容 1 次或多次 贪婪 \\\\d+:匹配 1 个或多个数字(非空)
    ? 匹配前面的内容 0 次或 1 次 贪婪 \\\\d?:匹配 0 个或 1 个数字
    {n} 匹配前面的内容恰好 n 次 贪婪 \\\\d{6}:匹配恰好 6 个数字(如验证码)
    {n,} 匹配前面的内容至少 n 次 贪婪 \\\\d{8,}:匹配至少 8 个数字(如密码)
    {n,m} 匹配前面的内容至少 n 次,最多 m 次 贪婪 \\\\d{6,18}:匹配 6-18 个数字(如账号)
    *? 匹配前面的内容 0 次或多次 非贪婪 (.*?):你之前提取 firstUrl 用到的非贪婪捕获
    +? 匹配前面的内容 1 次或多次 非贪婪 \\\\d+?:匹配最少 1 个数字,遇到非数字即停止
    关键区别:贪婪 vs 非贪婪(实战重点)

    String input = "num1=123&num2=456";
    // 贪婪匹配:\\\\d+(尽可能多匹配,直到最后一个数字)
    String greedyRegex = "num1=(\\\\d+)";
    Matcher greedyMatcher = Pattern.compile(greedyRegex).matcher(input);
    if (greedyMatcher.find()) {
    System.out.println("贪婪匹配结果:" + greedyMatcher.group(1)); // 输出:123(正确,因为&是非数字,停止)
    }

    // 若输入为 "num1=123456",贪婪和非贪婪结果一致;若输入为 "num1=123num2=456"
    String input2 = "num1=123num2=456";
    String nonGreedyRegex = "num1=(\\\\d+?)"; // 非贪婪匹配
    Matcher nonGreedyMatcher = Pattern.compile(nonGreedyRegex).matcher(input2);
    if (nonGreedyMatcher.find()) {
    System.out.println("非贪婪匹配结果:" + nonGreedyMatcher.group(1)); // 输出:1(最少匹配1个数字即停止)
    }

    分类 3:字符类(匹配指定范围的字符)

    用 [] 包裹,用于匹配「其中任意一个字符」,支持范围指定和排除逻辑,是验证场景的常用语法。

    语法含义说明Java 示例写法
    [abc] 匹配 a、b、c 中的任意一个字符 "[abc]"(匹配单个小写字母 a/b/c)
    [a-z] 匹配任意一个小写英文字母(a 到 z) "[a-z]"(范围匹配,用 – 连接)
    [A-Z] 匹配任意一个大写英文字母(A 到 Z) "[A-Z]"
    [0-9] 匹配任意一个数字(等价于 \\\\d) "[0-9]"
    [a-zA-Z0-9] 匹配任意一个大小写字母或数字(等价于 \\\\w,不含下划线) "[a-zA-Z0-9]"
    [^abc] 匹配除 a、b、c 之外的任意一个字符(^ 表示排除) "[^abc]"
    [^0-9] 匹配除数字之外的任意一个字符(等价于 \\\\D) "[^0-9]"
    示例(验证是否为小写字母)

    String regex = "^[a-z]+$"; // ^ 行首,$ 行尾,+ 至少1个
    String input1 = "abc";
    String input2 = "Abc123";
    System.out.println(Pattern.matches(regex, input1)); // 输出:true
    System.out.println(Pattern.matches(regex, input2)); // 输出:false

    分类 4:边界匹配器(匹配位置,非字符)

    用于匹配「字符串 / 行的边界位置」,不匹配具体字符,常用于「完整验证」(如手机号、邮箱的全量匹配)。

    原生正则Java 写法含义说明适用场景
    ^ ^ 匹配字符串的行首(整个输入的开头) 验证字符串是否以指定内容开头
    $ $ 匹配字符串的行尾(整个输入的结尾) 验证字符串是否以指定内容结尾
    \\b \\\\b 匹配单词边界(单词与非单词的分界) 提取单个单词、避免部分匹配
    \\B \\\\B 匹配非单词边界 匹配单词内部的内容
    关键示例(完整验证手机号,核心场景)

    // 手机号规则:1开头,第二位3-9,后面9位数字,完整匹配(不能有多余字符)
    String phoneRegex = "^1[3-9]\\\\d{9}$";
    String phone1 = "13812345678";
    String phone2 = "138123456789"; // 多1位
    String phone3 = "a13812345678"; // 前面有多余字符
    System.out.println(Pattern.matches(phoneRegex, phone1)); // true
    System.out.println(Pattern.matches(phoneRegex, phone2)); // false
    System.out.println(Pattern.matches(phoneRegex, phone3)); // false

    值得注意:

    在Pattern.matches()中,显式书写^和$是可选的,因为方法本身会自动隐含完整匹配逻辑,结果不受影响;

    在Matcher.find()(通用正则匹配)中,^和$是必不可少的,用于实现「完整字符串验证」,避免匹配到多余字符的子串;

    分类 5:捕获组与非捕获组(提取 / 复用内容)

    用 () 包裹,用于「捕获匹配结果」或「分组匹配」,分为「捕获组」(可提取、可反向引用)和「非捕获组」(仅匹配,不保存结果,节省资源)。

    1. 捕获组(常用)
    语法含义说明Java 示例
    (exp) 普通捕获组,编号从 1 开始(按左括号顺序) "(\\\\d{3})-(\\\\d{8})"(匹配座机号,分组 1 为区号,分组 2 为号码)
    (?<name>exp) 命名捕获组,给捕获组起名字,方便提取 "(?<area>\\\\d{3})-(?<number>\\\\d{8})"(命名 area 和 number)
    \\\\n 反向引用,引用第 n 个捕获组的内容(匹配与该组相同的内容) "(\\\\w)\\\\1"(匹配连续两个相同的单词字符,如 aa、11)
    示例(提取座机号的区号和号码)

    String regex = "(\\\\d{3})-(\\\\d{8})";
    String input = "北京区号:010-12345678,上海区号:021-87654321";
    Pattern pattern = Pattern.compile(regex);
    Matcher matcher = pattern.matcher(input);
    while (matcher.find()) {
    System.out.println("完整座机号:" + matcher.group(0)); // 第0组:整个匹配结果
    System.out.println("区号:" + matcher.group(1)); // 第1组:3位区号
    System.out.println("号码:" + matcher.group(2)); // 第2组:8位号码
    }

    2. 非捕获组(仅匹配,不提取)

    语法:(?:exp),用于分组匹配但不需要保存结果,适合复杂正则的分组逻辑,避免多余的捕获组占用资源。

    // 匹配 "abc" 或 "abd",用非捕获组分隔,无需提取分组结果
    String regex = "ab(?:c|d)";
    String input1 = "abc";
    String input2 = "abd";
    String input3 = "abe";
    System.out.println(Pattern.matches(regex, input1)); // true
    System.out.println(Pattern.matches(regex, input2)); // true
    System.out.println(Pattern.matches(regex, input3)); // false

    正则语法部分,我觉得捕获组,贪婪/非贪婪匹配,边界匹配的概念知道就很够用了。

    如有疏漏与错误还请在评论区讨论交流!

    赞(0)
    未经允许不得转载:171主机测评 » 【正则表达式详解|Java】从0学习实战够用
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址