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

非贪婪匹配

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

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

案例

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

贪婪匹配

java 复制代码
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));
        }
    }

输出结果:

java 复制代码
1010

非贪婪匹配

java 复制代码
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));
        }
    }

输出结果:

java 复制代码
1
0
1
0

正则表达式应用实例

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

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

java 复制代码
\\d{3}

运行结果:

java 复制代码
123
456

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

java 复制代码
^\\d\\d{2}$

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

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

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

1、汉字

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

java 复制代码
^[\u0391-\uffe5]+$

2、邮政编码

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

java 复制代码
^[1-9]\\d{5}$

3、QQ号码

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

java 复制代码
^[1-9]\\d{4,9}$

4、手机号码

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

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

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

5、URL

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

java 复制代码
https://blog.csdn.net/m0_64261982?spm=1000.2115.3001.5343

正则表达式:

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

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

java 复制代码
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

其中:

|-------------------------------|---------------------------------------------|---------------------------------------------------------------------|
| ^((https)://)? | https:// | 这里用了非贪婪匹配,网址可以省去协议 |
| ([\\w-]+\\.)+[\\w-]+ | blog.csdn.net | 把带 '.' 的用([\\w-]+\\.)+ 来匹配,后缀 .com或者 .net 这些用 [\\w-]+ 来匹配 |
| (\\/[\\w-?=&/%#.]*)?$ | m0_64261982?spm=1000.2115.3001.5343 | 后面主要处理的就是一些特殊符号,看情况增加 |

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

Pattern 类

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

比如,验证QQ号:

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

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

Matcher 类

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

我们以如下字符串为例:

java 复制代码
小美喜欢小明,小明也喜欢小美。

start 和 end 方法

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

java 复制代码
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());
        }

输出:

java 复制代码
=================
喜欢
2
4
=================
喜欢
10
12

replaceAll 方法

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

java 复制代码
    String content  = "清华大学是中国著名的大学";

        Pattern pattern = Pattern.compile("清华");
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()){
            String res = matcher.replaceAll("山西农业");
            System.out.println(res);
        }

输出:

java 复制代码
山西农业大学是中国著名的大学

反向引用

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

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

案例1-AA

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

java 复制代码
(\\d)\\1

案例2-AAAAA

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

java 复制代码
(\\d)\\1{4}

案例3-ABBA

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

java 复制代码
​(\\d)(\\d)\\2\\1
java 复制代码
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());
        }

输出:

java 复制代码
1221
2222

案例4

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

java 复制代码
\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}

案例5-结巴去重

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

java 复制代码
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);
}

简洁写法:

java 复制代码
content = Pattern.compile("(.)\\1+").matcher(content).replaceAll("$1");

输出:

java 复制代码
我要学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分割字符串

相关推荐
闲晨2 分钟前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
测开小菜鸟2 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
P.H. Infinity3 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天3 小时前
java的threadlocal为何内存泄漏
java
caridle3 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
^velpro^3 小时前
数据库连接池的创建
java·开发语言·数据库
苹果醋33 小时前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx
秋の花3 小时前
【JAVA基础】Java集合基础
java·开发语言·windows
小松学前端3 小时前
第六章 7.0 LinkList
java·开发语言·网络
Wx-bishekaifayuan3 小时前
django电商易购系统-计算机设计毕业源码61059
java·spring boot·spring·spring cloud·django·sqlite·guava