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分割字符串

相关文章
|
4天前
|
Java 程序员 API
Java并发基础:concurrent Flow API全面解析
java.util.concurrent.Flow定义了响应式编程的核心接口,促进了Java在异步数据处理和背压机制方面的标准化,这使得第三方库如Reactor和RxJava能够基于这些接口提供丰富的实现和功能,同时简化了响应式编程在Java中的使用,Flow API增强了Java在并发编程领域的灵活性,使得处理异步数据流变得更加自然和高效。
Java并发基础:concurrent Flow API全面解析
|
24天前
|
Java API
Java 8 时间和日期 API
Java 8 时间和日期 API
27 1
|
1天前
|
消息中间件 缓存 Java
Kafka Consumer java api 配置
Kafka Consumer java api 配置
|
1天前
|
IDE Java API
使用Java Web技术构建RESTful API的实践指南
使用Java Web技术构建RESTful API的实践指南
|
19天前
|
存储 Java 关系型数据库
Java8新特性:强大的Stream API
Java8新特性:强大的Stream API
22 0
|
19天前
|
Java
java获取各种时间,及格式
java获取各种时间,及格式
14 0
|
21天前
|
存储 运维 安全
Java常用类和基础API
Java常用类和基础API
32 0
|
23天前
|
存储 安全 Java
JAVA8实战 - 日期API
JAVA8实战 - 日期API
70 0
|
Java API Maven
api重复引用导致的诡异问题排查
api重复引用导致的诡异问题排查 最近一个项目上线前开发环境、测试环境都能正常打包并运行。然而到了准生产环境和生产环境则报一些诡异的错误信息: [INFO] ------------------------------------------------------------------------ [ERROR] Failed to execute goal org.
1034 0
|
19天前
|
SQL 安全 API
api接口是什么意思,api接口该如何防护呢?
api接口是什么意思,api接口该如何防护呢?

相关产品

  • 云迁移中心