Skip to content

正则表达式:文本处理的瑞士军刀

你一定遇到过这些场景:

  • 用户注册时,要验证手机号格式是否正确
  • 日志文件里,要提取所有 ERROR 开头的行
  • 表单提交时,要把 HTML 标签全部过滤掉
  • 爬虫抓取时,要从网页源码里提取邮箱和 URL

每次遇到这种"从一堆文本里找特定模式"的问题,你是不是都想写一堆 if-elsesubstring

那你就需要正则表达式了。


正则是什么?

正则表达式(Regular Expression)是描述字符串模式的一种语法。你可以把它理解为一把瑞士军刀——不是单一功能,而是多种文本处理能力的集合。

比如,你想匹配"以数字开头、以字母结尾的字符串",用自然语言描述很简单,但用代码怎么写?

java
// 没有正则的日子
if (str.length() > 0 && Character.isDigit(str.charAt(0))
    && Character.isLetter(str.charAt(str.length() - 1))) {
    // 匹配成功
}

// 有正则的日子
if (str.matches("^\\d.*[a-zA-Z]$")) {
    // 匹配成功
}

差距一目了然。


快速上手:5 分钟入门

第一个正则程序

java
import java.util.regex.*;

public class FirstRegex {
    public static void main(String[] args) {
        String text = "我的订单号是 20260315001,明天记得发货";
        
        // \\d 代表任意数字,+ 代表一个或多个
        Pattern p = Pattern.compile("\\d+");
        Matcher m = p.matcher(text);
        
        // find() 会找到所有匹配的子串
        while (m.find()) {
            System.out.println("找到: " + m.group());
        }
    }
}

输出:

找到: 20260315001

解释一下:

  • \\d 不是反斜杠 d,而是正则语法,代表"数字"
  • 在 Java 字符串里需要写成 \\d(因为单个 \ 需要转义)
  • + 是量词,表示前面的元素出现一次或多次
  • find() 每次调用都会找下一个匹配,直到没有为止

常用快捷字符

这是你最需要记住的几个"快捷方式":

写法含义等价于
\d数字[0-9]
\D非数字[^0-9]
\w单词字符[a-zA-Z0-9_]
\W非单词字符[^a-zA-Z0-9_]
\s空白字符[ \t\n\x0B\f\r]
.任意字符除了换行符

记住技巧:大写字母是大写的反义——\d 是数字,\D 就是"非数字"。

踩坑预警:点号

初学者最常犯的错误就是忘记转义点号。

java
public class DotTrap {
    public static void main(String[] args) {
        // 场景:检查文件名是否是 .txt 结尾
        
        // ❌ 错误写法
        String badPattern = ".txt";
        System.out.println("anythingtxt".matches(badPattern)); // true!因为 . 匹配任意字符
        
        // ✅ 正确写法:加点号转义
        String goodPattern = "\\.txt";
        System.out.println("anything.txt".matches(goodPattern)); // true
        System.out.println("anythingtxt".matches(goodPattern)); // false
    }
}

. 在正则里是"任意字符"的代名词,不是字面意思的点号。要匹配真正的点号,必须写成 \\.


实用场景:从日志里捞数据

看一个真实场景:解析日志文件中的关键信息。

java
import java.util.regex.*;

public class LogParser {
    public static void main(String[] args) {
        String log = "2026-03-22 10:30:15 ERROR [OrderService] 订单处理失败,订单号: ORD-20260322-001";
        
        // 日志正则分解
        String logPattern = "(\\d{4}-\\d{2}-\\d{2}) (\\d{2}:\\d{2}:\\d{2}) (\\w+) .*订单号: (.+)";
        
        Pattern p = Pattern.compile(logPattern);
        Matcher m = p.matcher(log);
        
        if (m.matches()) {
            System.out.println("日期: " + m.group(1));  // 2026-03-22
            System.out.println("时间: " + m.group(2));  // 10:30:15
            System.out.println("级别: " + m.group(3));  // ERROR
            System.out.println("订单号: " + m.group(4)); // ORD-20260322-001
        }
    }
}

分组捕获() 里的内容会被捕获,通过 m.group(1)m.group(2) 提取。


三种常用操作:验证、提取、替换

1. 验证:matches()

检查整个字符串是否符合模式:

java
public class ValidationDemo {
    public static void main(String[] args) {
        // 验证手机号
        String phone = "13812345678";
        boolean valid = phone.matches("^1[3-9]\\d{9}$");
        System.out.println("手机号有效: " + valid);  // true
        
        // ❌ 常见的错误:忘记 ^ 和 $
        String badPhone = "x13812345678x";
        boolean invalid = badPhone.matches("1[3-9]\\d{9}");  // true!因为没有锚定
        System.out.println("误判为有效: " + invalid);
    }
}

教训:验证时一定要加 ^$,否则只检查"是否包含"而非"是否完全匹配"。

2. 提取:find()

从文本中找出匹配的片段:

java
public class ExtractDemo {
    public static void main(String[] args) {
        String html = "邮箱: test@example.com,电话: admin@test.org";
        
        Pattern p = Pattern.compile("\\w+@\\w+\\.\\w+");
        Matcher m = p.matcher(html);
        
        while (m.find()) {
            System.out.println("提取: " + m.group());
        }
    }
}

输出:

提取: test@example.com
提取: admin@test.org

3. 替换:replaceAll()

把匹配的部分替换成别的内容:

java
public class ReplaceDemo {
    public static void main(String[] args) {
        String text = "原价 299 元,双十一特价 199 元,错过等一年!";
        
        // 把所有数字替换成 #
        String result1 = text.replaceAll("\\d+", "#");
        System.out.println(result1);  // 原价 # 元,双十一特价 # 元,错过等一年!
        
        // 只替换第一个数字
        String result2 = text.replaceFirst("\\d+", "XXX");
        System.out.println(result2);  // 原价 XXX 元,双十一特价 199 元,错过等一年!
    }
}

一张图记住核心语法

位置锚点: ^ 开头  $ 结尾  \b 单词边界
字符类:   \d 数字  \w 字母  \s 空白  . 任意
量词:     * 0+   + 1+   ? 0-1   {n} {n,} {n,m}
分组:     () 捕获  (?:) 非捕获

总结

正则表达式是处理文本的利器,掌握它只需要记住几点:

  1. 快捷字符\d 是数字,\w 是字母数字下划线,\s 是空白
  2. 量词+ 是一个或多个,* 是零个或多个,? 是零个或一个
  3. 转义:真正匹配 . 要写 \\.,匹配 \ 要写 \\\\
  4. 锚点:验证时别忘加 ^$
  5. 分组:用 () 捕获,$1$2 引用

学会了这些,你就能写出:

  • 邮箱验证:^\\w+@\\w+\\.\\w+$
  • 手机号:^1[3-9]\\d{9}$
  • 提取数字:\\d+

下一节我们深入讲语法细节:正则表达式语法

基于 VitePress 构建