Java 正则表达式

1、Java使用正则表达式

java.util.regex 包是 Java 标准库中用于支持正则表达式操作的包。[1]

包括以下三个类:

  • Pattern 类:
    Pattern 对象是一个正则表达式的编译表示。调用 Pattern 对象的 compile 方法来获得一个 Pattern 对象。
    如:Pattern pattern = Pattern.compile("[0-9]*");
  • Matcher 类:
    Matcher 对象是对输入字符串进行解释和匹配操作的引擎。调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。
    如:Matcher isNum = pattern.matcher(str);
  • PatternSyntaxException:
    PatternSyntaxException 是一个非强制异常类,它表示一个正则表达式模式中的语法错误。

 

1.1、matches() 判断字符串中是否匹配

字符串与正则表达式匹配,完全匹配:true,不完全匹配:false

// 1. 编译正则表达式,生成Pattern对象
Pattern pattern = Pattern.compile("a*b");
        
// 2. 创建Matcher对象,关联待匹配的字符串
Matcher matcher = pattern.matcher("aaaaab");
        
// 3. 执行匹配操作
boolean matchFound = matcher.matches();

System.out.println(matchFound); // 输出: true

1.2、find() 查找匹配项

查找匹配的元素

find():返回是否有找到

group():返回查找到的下一个

start():返回起始索引

end(): 返回结束索引

Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher("dde123eee456fff");
while (matcher.find()) {
    System.out.println("找到:"+matcher.group()+", 开始位置:"+matcher.start()+",结束位置:"+matcher.end());
}
// 输出:
// 找到:123, 开始位置:3,结束位置:6
// 找到:456, 开始位置:9,结束位置:12

1.3、lookingAt() 前缀匹配模式

判断字符串是否以XX开头,是:true,否:false

Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher("123eee");
System.out.println(matcher.lookingAt()); 

//输出: true

 

2、正则表达式语法

元字符匹配[2]

字符 描述
. 匹配除换行符以外的任意字符
^ 匹配字符串的开始位置
$ 匹配字符串的结束位置
* 匹配前面的子表达式零次或多次
+ 匹配前面的子表达式一次或多次
? 匹配前面的子表达式零次或一次
{n} 匹配前面的子表达式恰好n次
{n,} 匹配前面的子表达式至少n次
{n,m} 匹配前面的子表达式至少n次,至多m次
[] 匹配方括号中指定的任意一个字符
[^] 匹配不在方括号中指定的任意一个字符
() 标记一个子表达式的开始和结束位置
| 表示或关系,匹配两个或多个选项之一

预定义字符匹配

字符 表达式 描述
\d [0-9] 匹配一个数字字符
\D [^0-9] 匹配一个非数字字符
\w [a-zA-Z_0-9] 匹配一个单词字符(字母、数字、下划线)
\W [^a-zA-Z_0-9] 匹配一个非单词字符
\s [ \t\n\x0B\f\r] 匹配一个空白字符(空格、制表符、换行符等)
\S [^ \t\n\x0B\f\r] 匹配一个非空白字符

 

3、注意事项

  1. 复用Pattern对象
    避免在循环中重复编译相同的正则表达式,应将编译后的Pattern对象缓存并复用。
  2. 优先使用String类的方法
    对于简单的字符串操作,如startsWith()endsWith()indexOf()等,应优先使用String类的方法,比正则表达式效率更高。

 

4、常见案例

4.1、使用圆括号()分别提取

使用圆括号()可以将正则表达式中的部分内容分组,每个分组可以被单独捕获和引用。分组编号从1开始,0表示整个匹配结果。[2]

比如:分别提取邮箱的用户名和域名

public class GroupExample { 
   public static void main(String[] args) {
        String email = "test.user@example.com";
        String regex = "([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})";
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(email);
        
        if (matcher.matches()) {
            System.out.println("完整匹配: " + matcher.group(0));  // 整个匹配结果
            System.out.println("用户名: " + matcher.group(1));    // 第一组
            System.out.println("域名: " + matcher.group(2));      // 第二组
        }
   } 
}

//完整匹配: test.user@example.com 
//用户名: test.user 
//域名: example.com

4.2、贪婪匹配与非贪婪匹配

  1. 贪婪匹配
    默认情况下,正则表达式的量词(如*、+、{n,m})是贪婪的,会尽可能多地匹配字符。例如,<.*> 会匹配整个 HTML 标签。
  2. 非贪婪匹配
    在量词后面加上?,可以将贪婪匹配转换为非贪婪匹配,尽可能少地匹配字符。如 <.*?>,只匹配最短的内容。
public class GreedyVsNonGreedy {
    public static void main(String[] args) {
        String text = "<html><body><h1>Hello</h1></body></html>";
        
        // 贪婪匹配
        String greedyRegex = "<.*>";
        Pattern greedyPattern = Pattern.compile(greedyRegex);
        Matcher greedyMatcher = greedyPattern.matcher(text);
        
        if (greedyMatcher.find()) {
            System.out.println("贪婪匹配: " + greedyMatcher.group());
        }
        
        // 非贪婪匹配
        String nonGreedyRegex = "<.*?>";
        Pattern nonGreedyPattern = Pattern.compile(nonGreedyRegex);
        Matcher nonGreedyMatcher = nonGreedyPattern.matcher(text);
        
        while (nonGreedyMatcher.find()) {
            System.out.println("非贪婪匹配: " + nonGreedyMatcher.group());
        }
    }
}


//输出:
贪婪匹配: <html><body><h1>Hello</h1></body></html>
非贪婪匹配: <html>
非贪婪匹配: <body>
非贪婪匹配: <h1>
非贪婪匹配: </h1>
非贪婪匹配: </body>
非贪婪匹配: </html>

4.3、断言

  1. (?=...) 正向前瞻
    匹配后面跟着特定模式的地方,比如:a(?=b) 匹配 a,但要求其后必须是 b
  2. (?!...) 负向前瞻
    匹配后面不跟着特定模式的地方,比如:a(?!b) 匹配 a,但要求其后不跟 b

 

4.4、常见正则表达式

匹配 正则
邮箱 ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$
身份证 ^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9Xx]$
URL ^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$
日期(YYYY-MM-DD) ^\d{4}-\d{2}-\d{2}$
IPv4地址 ^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$
HTML标签 <([a-z]+)([^<]+)*(?:>(.*?)<\/\1>|\s*\/>)
中文字符 ^[\u4e00-\u9fa5]+$
邮政编码(中国) ^\d{6}$
密码强度(8位且含字母和数字) ^(?=.*\d)(?=.*[a-zA-Z]).{8,}$
正整数 ^[1-9]\d*$
负整数 ^-\d+$
整数 ^-?[1-9]\d*$
整数(含前导零) ^-?\d+$
小数 ^-?(?:0|[1-9]\d*)\.\d+$
科学计数法 ^-?\d+(?:\.\d+)?[eE][+-]?\d+$
简写小数(允许 .5 或 0.5 格式) ^-?\d*\.?\d+$

[3]

 

参考资料

  1. Java正则表达式.菜鸟教程
  2. Java正则表达式完全指南.AA-代码批发V哥
  3. 常用正则表达式