目录

Java 正则前置须知

Java 正则常用语法分类详解

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

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

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

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

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

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

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

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

1. 捕获组(常用)

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

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


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

Java 正则前置须知

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

Java 正则常用语法分类详解

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

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

原生正则 Java 写法 含义说明 适用示例
. . 匹配除「换行符 \n」外的任意单个字符 匹配 a1@/
\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] 匹配 abc 中的任意一个字符 "[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] 匹配除 abc 之外的任意一个字符(^ 表示排除) "[^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"(匹配连续两个相同的单词字符,如 aa11
示例(提取座机号的区号和号码)
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

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

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

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐