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

其中:

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

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

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

 

 

 

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

让线程再跑一会

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值