Java 正则表达式【非贪婪匹配、格式验证、反向引用、API】

简介: Java 正则表达式【非贪婪匹配、格式验证、反向引用、API】

非贪婪匹配

非贪婪匹配的元字符是问号 ?

当此字符跟在任何其他限定符(*、+、?、{n}、{m}、{n,m})之后,匹配模式是 "非贪心的"。非贪心的意思就是每次匹配搜索到的尽可能短的字符串,可以是0个

案例

对比贪婪匹配和非贪婪匹配

贪婪匹配

public static void main(String[] args) {
        String content  = "hello1010";
        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()){
            System.out.println(matcher.group(0));
        }
    }

输出结果:

1010

非贪婪匹配

public static void main(String[] args) {
        String content  = "hello1010";
        Pattern pattern = Pattern.compile("\\d+?");
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()){
            System.out.println(matcher.group(0));
        }
    }

输出结果:

1
0
1
0

正则表达式应用实例

对字符串进行如下格式验证:

注意:格式验证不同于普通的匹配,格式匹配通常使用字符匹配符、定位符和限定符三种来进行匹配,尤其是限定符(定位符 ^ 、$),比如我们要判断 "123456"是不是三位数,如果我们使用如下的正则表达式:

\\d{3}

运行结果:

123
456

但其实是不匹配的,所以我们需要加定位符:

^\\d\\d{2}$

意思就是匹配以一位数字为开头,两位数字为结尾的字符串。

下面为了避免重复代码,我把模板放到这,只需要替换正则表达式的表达式即可。

        Pattern pattern = Pattern.compile("");
        Matcher matcher = pattern.matcher(content);
        if (matcher.find()){
            System.out.println("满足格式");
        }

1、汉字

汉字的编码为  \u0391 到 \uffe5。

^[\u0391-\uffe5]+$

2、邮政编码

要求:是1~9开头的一个六位数

^[1-9]\\d{5}$

3、QQ号码

要求:是1-9开头的一个(5-10位数)

^[1-9]\\d{4,9}$

4、手机号码

必须 13,14,15,18 开头的11位数。

我们可以使用小括号和竖线符号表示逻辑或,也可以使用中括号进行范围表示。

^(13|14|15|18)\\d{9}$
//或者
^(1[3458])\\d{9}$

5、URL

URL 的匹配很重要,尤其是在网络爬虫中会经常用到。

https://blog.csdn.net/m0_64261982?spm=1000.2115.3001.5343

正则表达式:

^((http|https)://)?([\w-]+\.)+[\w-]+(\/[\w-?=&/%#.]*)?$

注意:我们这里的正则表达式中的括号都是捕获分组,如果希望不捕获的话,可以在左半括号加一个问号?,这样就成了非捕获分组,非捕获分组的内容不会保存到Matcher类中的groups数组中去,而捕获分组的内容会保存到内存中,可以通过Matcher.group(int group)的方式从groups数组提取出来或者显示命名的分组可以通过自定义的组名提取出来(详细可以看我第二篇博客关于捕获分组的部分)。

System.out.println(matcher.group(0));    //https://blog.csdn.net/m0_64261982?spm=1000.2115.3001.5343
System.out.println(matcher.group(1));    //https://
System.out.println(matcher.group(2));    //https
System.out.println(matcher.group(3));    //csdn.
System.out.println(matcher.group(4));    ///m0_64261982?spm=1000.2115.3001.5343

image.png注意: [?.*] 中括号里的点和问号只代表本身 没有特殊含义。

Pattern 类

之前我要做一些格式验证的话需要写很多代码,其实我们可以直接使用Pattern类中的一个matches方法,它可以对传入的正则表达式和字符串参数直接做一个整体匹配

比如,验证QQ号:

        System.out.println(Pattern.matches("^[1-9]\\d{4,9}$","3493247023"));

这样就可以极大地简洁代码,而不用去调用 Matcher 去一个个匹配。总之,Pattern.matches()适合做整体匹配,但不能做字符串中满足某一正则表达式的所有子串的匹配,所以看情况使用。

Matcher 类

这里介绍一些Matcher对象的其他方法。

我们以如下字符串为例:

小美喜欢小明,小明也喜欢小美。

start 和 end 方法

start 和 end 会输出匹配到的字符串的下标

String content  = "小美喜欢小明,小明也喜欢小美。";
        Pattern pattern = Pattern.compile("喜欢");
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()){
            System.out.println("=================");
            System.out.println(matcher.group(0));
            System.out.println(matcher.start());
            System.out.println(matcher.end());
        }

输出:

=================
喜欢
2
4
=================
喜欢
10
12

replaceAll 方法

把满足正则表达式的子串内容替换为参数的内容。

    String content  = "清华大学是中国著名的大学";
        Pattern pattern = Pattern.compile("清华");
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()){
            String res = matcher.replaceAll("山西农业");
            System.out.println(res);
        }

输出:

山西农业大学是中国著名的大学

反向引用

反向引用和分组、捕获是有关系的,下面是反向引用的概念:

圆括号的内容被捕获后,可以在这个括号后使用,从而写出一个比较实用的匹配模式,这个我们称之为反向引用,这种引用既可以是在正则表达式内部,用 \\分组号;也可以是在正则表达式外部,用 $分组号

案例1-AA

匹配两个连续的相同数字。

(\\d)\\1

案例2-AAAAA

匹配五个连续的相同数字。

(\\d)\\1{4}

案例3-ABBA

找出字符串中所有满足 ABBA 型的子串。

​(\\d)(\\d)\\2\\1
String content = "12212121212222";
        String regex = "(\\d)(\\d)\\2\\1";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()){
            System.out.println(matcher.group());
        }

输出:

1221
2222

案例4

检索商品编号:形式如:12321-333999111 这样的号码,前面是一个五位数,然后是一个-,最后是一个AAABBBCCC型的9位数。

\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}

案例5-结巴去重

核心语句:(.)\\1+ 代表至少有两个重复字符的子串。

public static void main(String[] args) {
        String content = "我...我要...学学学学...Java!";
        // 1. 去掉所有的.
        Pattern pattern = Pattern.compile("\\.");
        Matcher matcher = pattern.matcher(content);
        content = matcher.replaceAll("");
        // 2. 去掉重复的字
        pattern = Pattern.compile("(.)\\1+");
        matcher = pattern.matcher(content); //matcher 对象需要重新赋值
        content = matcher.replaceAll("$1");
        System.out.println(content);
}

简洁写法:

content = Pattern.compile("(.)\\1+").matcher(content).replaceAll("$1");

输出:

我要学Java!

String 类中的正则表达式

1、String.replaceAll(String regex,String replacement)

将content中满足正则表达式regex的子串替换为 replacement。

2、public boolean matches(String regex)

判断字符串是否满足正则表达式regex,相当于Pattern.matches(String regex,String content)。

3、public String[] split(String regex)

按照正则表达式regex分割字符串

相关文章
|
3月前
|
Java API 数据处理
Java新特性:使用Stream API重构你的数据处理
Java新特性:使用Stream API重构你的数据处理
|
3月前
|
Java 大数据 API
Java Stream API:现代集合处理与函数式编程
Java Stream API:现代集合处理与函数式编程
253 100
|
3月前
|
Java API 数据处理
Java Stream API:现代集合处理新方式
Java Stream API:现代集合处理新方式
286 101
|
3月前
|
并行计算 Java 大数据
Java Stream API:现代数据处理之道
Java Stream API:现代数据处理之道
250 101
|
4月前
|
存储 Java API
Java Stream API:现代数据处理之道
Java Stream API:现代数据处理之道
371 188
|
4月前
|
存储 Java API
Java Stream API:现代数据处理之道
Java Stream API:现代数据处理之道
284 92
|
2月前
|
Java Go 开发工具
【Java】(8)正则表达式的使用与常用类分享
正则表达式定义了字符串的模式。正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别。
229 1
|
3月前
|
安全 Java API
使用 Java 构建强大的 REST API 的四个基本技巧
本文结合探险领域案例,分享Java构建REST API的四大核心策略:统一资源命名、版本控制与自动化文档、安全防护及标准化异常处理,助力开发者打造易用、可维护、安全可靠的稳健API服务。
215 2
|
3月前
|
存储 数据可视化 Java
Java Stream API 的强大功能
Java Stream API 是 Java 8 引入的重要特性,它改变了集合数据的处理方式。通过声明式语法,开发者可以更简洁地进行过滤、映射、聚合等操作。Stream API 支持惰性求值和并行处理,提升了代码效率和可读性,是现代 Java 开发不可或缺的工具。
Java Stream API 的强大功能
|
4月前
|
安全 Java API
Java日期时间API:从Date到Java.time
本文深入解析了Java 8中引入的全新日期时间API,涵盖LocalDate、LocalTime、LocalDateTime、ZonedDateTime等核心类的使用,以及时间调整、格式化、时区处理和与旧API的互操作。通过实例对比,展示了新API在可变性、线程安全与易用性方面的显著优势,并提供迁移方案与实战技巧,助你掌握现代Java时间处理的最佳实践。