Java正则表达式总结 ^_^

引用

B站韩顺平正则表达式精讲

菜鸟教程

正则表达式30分钟入门教程

Java正则表达式介绍

  正则表达式(Regular Expression)—— 是一种对字符串操作的逻辑公式,用事先定义好的特殊字符和特殊字符组合来组成一个“规则字符串”。再利用这个“规则字符串”来表达对字符串的过滤。

  正则表达式不是只java才有,很多语言都支持正则表达式进行字符串操作。

Java.until.regex包主要包括如下三个类
  • Pattern类

   pattern对象是一个正则表达式的编译表示。Pattern类没有公共构造方法(意思是不能new Pattern来构造对象)。要创建一个Pattern对象,必须首先调用其公共静态编译方法Pattern.complie(regex),返回一个Pattern对象。该方法接收一个正则表达式作为它的第一参数

//可以直接调用Pattern类的matchas()方法,进行全匹配!(指整个字符串都满足正则表达式)

String content = "123";
String regStr = "//d+"
System.out.println(Pattern.matchas(regStr,content))

//该方法会返回一个Boolean值,这里会打印出true。它不会返回匹配到的字符串
  • Matcher类

  Matcher对象是对输入字符串进行解释和匹配操作的引擎。与Pattern类一样,Matcher也没有公共构造方法。需要调用Pattern对象的matcher方法来获得一个Matcher对象,pattern.matchar(content)

在这里插入图片描述

实例

public static void main(String[] args) {
    String content = "mikasa biubu hellow word mikasagaf";
    String regStr = "mikasa";
    Pattern pattern = Pattern.compile(regStr);
	Matcher matcher = pattern.matcher(content);
    while(matcher.find()){
    	System.out.println("======");
        System.out.println(matcher.start());
        System.out.println(matcher.end());
        System.out.println("字符:"+content.substring(matcher.start(), matcher.end()));
    }
        //返回的结果为
        //======
        //0
        //6
        //字符:mikasa
        //======
        //25
        //31
        //字符:mikasa

    //整体匹配,常用于验证某个字符串是否满足某个规则
    System.out.println("整体匹配:"+matcher.matches());//这里返回false

    //将匹配到的mikasa替换为eren
    String newContent = matcher.replaceAll("eren");
    System.out.println(newContent);
        //打印内容:eren biubu hellow word erengaf
    }
  • PatternSyntaxException是一个非强制异常类,他表示一个正则表达式模式中的语法错误

     以下实例使用正则表达式查找文本字符串中所有连续的4个数字

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Demo01 {
    public static void main(String[] args) {
        String content = "出生于医学世家;1958年8月,在第一届全运会的比赛测验中,以54秒2的成绩,打破了当时54秒6的400米栏全国纪录。" +
                "1960年毕业于医学院(;2007年获英国荣誉博士;2007年10月重点实验室主任;" +
                "2014年获香港荣誉理学博士2019年被聘为中国医学科学院学部委员2020年8月11" +
                "予2020年度科学与技术成就奖”。";
        //目标:匹配所有的四个数字(年份)
        //1、编写正则
        String regStr = "\\d\\d\\d\\d";//说明:\\d表示一个任意的数字
        
        //2、创建模式对象[正则表达式对象]
        Pattern pattern = Pattern.compile(regStr);
        
        //3.创建一个匹配器
        //说明:创建匹配器matcher,按照 正则表达式规则 去匹配 content字符串
        Matcher matcher = pattern.matcher(content);

        //4、开始匹配
        while(matcher.find()){
            System.out.println("找到:"+ matcher.group(0));
        }
    }
}
  • 这里详细说明一下 matcher.find() 完成的任务:
  1. 根据指定的规则,定位满足规则的子字符串(如第一个匹配的就是1958

  2. 找到后,将子字符串开始的索引记录到matcher对象的属性 int[] groups,groups[0]=11把该子字符串结束的索引+1的值记录到groups[1]=15

  3. 同时记录oldLast的值,即子字符串结束的索引+1的值。下次执行find方法时即从oldLast开始匹配
    在这里插入图片描述

在这里插入图片描述

  • matcher.group(0)分析

    • 根据groups[0]=11和group[1]=15记录的位置,从content开始截取子字符串的范围就是[11,15),包含11但是不包含15
//matcher对象group方法的源码为
    public String group(int group) {
        if (first < 0)
            throw new IllegalStateException("No match found");
        if (group < 0 || group > groupCount())
            throw new IndexOutOfBoundsException("No group " + group);
        if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
            return null;
        return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
    }
java正则表达式中的分组

​ java中也叫做捕获组,是指把多个字符当作一个单独单元处理的方法,它通过对括号内的字符分组来创建。例如,正则表达式(mikasa)就创建了单一分组

​ 捕获组是通过从左自右计算其括号开始编号的,例如在((A)(B(C))),有四个这样的组:

  • group(1)为 ((A)(B©))

  • group(2)为 (A)

  • group(3)为 (B©)

  • group(4)为 ©

    可以通过调用matcher对象的groupCount方法来查看表达式中有多少个分组,groupCount 方法返回一个 int 值,表示matcher对象当前有多个捕获组。还有一个特殊的分组也就是matcher.group(0),他总是代表整个表达式。该组不包括在groupCount的返回值中

实例代码(将上面的代码中的正则表达式变为(\\d\\d)(\\d\\d))

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Demo01 {
    public static void main(String[] args) {
        String content = "出生于医学世家;1958年8月,在测验中,以54秒2的成绩,打破了当时54秒6的400米栏全国纪录。" +
                "1960年毕业于医学院);2007年获英国荣誉博士;2007年10月实验室主任;" +
                "2014年获香港中文大学荣誉理学博士2019年被聘为委员2020年8月11日" +
                "选2020年“全国教书育人楷模”名单。"+
                "予2020年12月15日,获颁香港理工大学荣誉博士学位;12月19日,获授澳门特区政府颁发的大莲花荣誉勋章。";
        String regStr = "(\\d\\d)(\\d\\d)";
        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while(matcher.find()){
            System.out.println("找到:"+ matcher.group(0));
            System.out.println("组1:"+ matcher.group(1));
            System.out.println("组2:"+ matcher.group(2)
        }
    }
}

第一次find()
在这里插入图片描述

Java正则表达式语法

  如果想要灵活的运用正则表达式,必须了解其中各种元字符的功能,元字符从功能上大致分为

  1. 限定符

  2. 选择匹配符

  3. 分组、捕获、反向引用

  4. 特殊字符

  5. 字符匹配符

  6. 定位符

java中的转义符是与其他语言有区别的!

  在其他语言中,\\表示:在正则表达式中插入一个普通的(字面上的)反斜杠,无任何特殊意义)

​   在java中,\\表示:在正则表达式中插入一个反斜杠,所以其后的字符具有特殊意义

限定符

  用于指定其前面的字符或组合项连续出现了多少次

符号含义示例解释
*零次或多次匹配前面的字符或子表达式。等效于{0,}zo*zo*匹配z和zo、zoo、zooo…。
+一次或多次匹配前面的字符或子表达式。等效于{1,}m+(abc)+以至少一个m开头,后接任意个abc的字符串
零次或一次匹配前面的字符表达式。m+abc?以至少一个m开头 ,后接ab或abc的字符串
{n}n是非负整数。正好匹配n次。[abcd]{3}由abcd中字母组成的任意长度为3的字符串
{n,}n是非负整数。至少匹配n次。[abcd]{3,}由abcd中字母组成的任意长度不小于3的字符串
{n,m}n和m是非负整数,其中n<=m。至少匹配n次,至多匹配m次。[abcd]{3,5}由abcd中字母组成的任意长度不小于3不大于5的字符串
选择匹配符
符号含义示例解释
|匹配 “|” 之前或之后的表达式ab|cdab或者cd
分组组合和反向引用符

  组就是把多个字符当作单一的单元。分组是通过在()小括号内放置正则表达式来创建的,每对小括号对应一个组。

  捕获是把正则表达式中分组匹配(或者说是子表达式)中的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用

  • 常用分组
常用分组构造形式说明
(pattern)非命名捕获。捕获匹配的子字符串。编号为零的第一个捕获是由整个正则表达式模式匹配的文本,其它捕获结果则根据左括号的顺序从1开始自动编号
(?pattern)命名捕获。将匹配的子字符串捕获到一个组名称或编号名称中。用于name的字符串不能包含任何标点符号,并且不能以数字开头。可使用单引号代替尖括号,例如(?‘name’

  非命名捕获分组在上面讲述中已经提及过。下面通过一个具体实例讲述命名分组

public class Demo02 {
    public static void main(String[] args) {
        String content = "1960年毕业于北京医学院(今北京大学医学部);2007年获英国爱丁堡大学荣誉博士";
        String regex = "(?<group1>\\d\\d)(?<group2>\\d\\d)";
        //注:组的命名不能使用中文!
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(content);
        while(matcher.find()){
            System.out.println("匹配到了"+matcher.group(0));
            System.out.println("第一个分组的内容"+matcher.group(1));
            System.out.println("第一个分组的内容(通过组名的方式获取)"+matcher.group("group1"));
            System.out.println("第而个分组的内容"+matcher.group(2));
            System.out.println("第而个分组的内容(通过组名的方式获取)"+matcher.group("group2"));
            System.out.println();
        }
    }
}

运行结果为:
在这里插入图片描述

  • 特别分组(非捕获分组,不能使用matcher.group(1))
特别分组构造形式说明
(?:pattern)匹配pattern,但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用“or”字符(|)组合模式部件的情况很有用。例如,'indust(?:y|ies) 是比industy|industries更优的表达式
(?=pattern)也是一个**非捕获匹配。**例如,“windows(?=95|98|NT|2000)” 能匹配"windows2000" "windows95"中的windows,但不能匹配"windows2001"中的windows
(?!pattern)该表达式匹配不处于匹配pattern字符串的起始点的搜索字符。它是一个 非捕获匹配( “!” 可以理解为取反)。例如windows(?=95|98|NT|2000)" 能匹配"windows2001" 中的windows,但不能匹配"windows2000"中的windows

实例

String content = "mikasa13biubiubiu";
String regex = "mikasa(?:13|14)";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);
while(matcher.find()){
    System.out.println("匹配到了"+matcher.group(0));
    //System.out.println("匹配到了"+matcher.group(1));
}
//打印出的内容为:mikasa13

这里需要说明一点,正则表达式mikasa(?:13|14)mikasa(13|14)是会打印相同的结果,但区别在哪呢?前者是一个非捕获匹配,特殊分组,不捕获该匹配的子表达式,也就是说打印group(1)会出现报错。但后者是非命名捕获匹配,常用分组,打印group(1)的结果是13。

String content = "mikasa13biubmikasa15iubiu";
String regex = "mikasa(?=13|14)";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);
while(matcher.find()){
    System.out.println("匹配到了"+matcher.group(0));
}
//打印出的内容只有一个:mikasa
//实际上匹配到的是mikasa13中的mikasa
String content = "mikasa13biubmikasa15iubiu";
String regex = "mikasa(?=13|14)";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);
while(matcher.find()){
    System.out.println("匹配到了"+matcher.group(0));
}
//打印出的内容只有一个:mikasa
//实际上匹配到的是mikasa15中的mikasa
  • 反向引用

反向引用是基于分组的,它允许重复正则而不需要再写一次。可以通过\\# 来引用前面定义的组,# 是组的序号,从1开始。正则引擎在处理匹配时,要求反向引用的组匹配的内容必须是一样的:即 (\\d\\d\\d)\\1 会匹配到123123,而不会匹配123456

实例

匹配两个连续相同的数字: (\\d)\\1
匹配五个连续相同的数字:(\\d)\\1{4}
匹配一个四位数,要求个位和千位相同,十位和百位相同:(\\d)(\\d)\\2\\1
匹配类似12321-333999111的商品编码。要求满足前面是一个五位数,然后是一个-,再是一个九位数要求连续三位要相同:\\d{5}-(\\d)\\1{1}(\\d)\\2{2}(\\d)\\3{2}
字符匹配符
符号含义示例解释
[ ]指可接受的字符集[efgh]表示e、f、g、h中的任意一个字符
[^]不接收的字符集[^abc]除a、b、c之外的任意一个字符,包括数字和特殊符号
-连字符A-Z任意单个大写字符
.通配符,匹配除\n以外的任何字符a…b以a开头,b结尾,中间包括2个任意字符且长度为4的字符串
\d匹配单个数字字符,相当于[0-9]\d{3}(\d)?包含三个或四个数字的字符串
\D匹配单个非数字字符,相当于[^0-9]\D(\d)*以单个非数字字符开头,后接任意个数字的字符串
\w匹配单个数字、大小写字母字符,相当于[0-9a-zA-Z]\d{3}\w{4}以三个数字字符开头长度为7的数字字母字符
\W匹配单个非数字、大小写字母字符,相当于[^0-9a-zA-Z]\W+\d{2}以至少1一个非数字、字母开头,2个数字字符结尾的字符串。如#29、#¥%10
定位符

  规定要匹配的字符串出现的位置,比如在字符串的开始还是结束的位置

符号含义示例解释
^指定起始符^\d+[a-z]*以至少一个数字开头,后面接任意个小写字母的字符串
$指定结束符^\d\-[a-z]+$以一个数字开头,后接连接字符“-”,并以至少一个小写字母结尾的字符串
\b匹配目标字符串的边界han\b这里说的字符串边界指的是子串间有空格,或者是目标字符串结束的位置
\B匹配目标字符串的非边界han\B和\b的含义相反

一些实例

  • 匹配字符串是否全是汉字 ^[\u0391-\uffe5]$

  • 邮政编码(1-9开头的6位数) ^[1-9]\\d{5}$

  • 手机号(必须13,14,15,18开头) ^1[3458]\\d{9}$

  • url地址 ^http[s]?://([\\w]+\\.)+[\\w]+(/[\\w-_=?#&.\*%]\*)\*$

  • ip地址(ipv4共四段,每段用.分隔,是0-255间的十进制数)

    • 将0-255用正则表达式表示,需要分段考虑
取值区间正则写法
250-25525[0-5]
200-2492[0-4]\d
100-1991\d{2}
0-99[1-9]?\d
    • 合并后的表达式为((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)
    • 实际上在这基础上是还能简化的,虽然ip地址中每个数字都不能大于255,但像01.02.03.04,这种前面带有0的数字也是ip地址。ip地址里的数字可以包含有前导0。所以可以将0-199归为一整段为([01]?\\d?\\d)。简化后的表达式为((25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d?\\d)
  • 结巴去重

    • 这里运用到了反向引用的知识点,内部的反向引用用//1,外部的用$1
    • 把类似:“我…我要…学学学学…Java“,通过正则表达式修改为“我要学Java”
    public static void main(String[] args) {
        String content = "我...我要...学学学学....Java";

        //1.去掉所有的.
        Pattern pattern = Pattern.compile("\\.");
        Matcher matcher = pattern.matcher(content);
        String content1 = matcher.replaceAll("");

        //2.去除重复的汉字
        //用"(.)\\1+"匹配重复的数字
        //用 外部的反向引用$1来替换匹配到的内容
        pattern = Pattern.compile("(.)\\1+");
        matcher = pattern.matcher(content1);
        while(matcher.find()){
            System.out.println("匹配到的内容是:"+matcher.group(0));
        }
        //打印内容是
        //  匹配到的内容是:我我
        //  匹配到的内容是:学学学学

        //替换
        String content2 = matcher.replaceAll("$1");
        System.out.println(content2);
        //我要学Java
    }

String类中的正则表达式

  • 替换功能
public String **replaceAll**(String regex,String replacement)
//将Java7和Java8用Java代替

String content = "2011年,甲骨文公司举行了全球性的活动,以庆祝Java7的推出,随后Java7正式发布。2014年,甲骨文公司发布了Java8正式版";
String content1 = content.replaceAll("Java[78]","Java");
System.out.println(content1);
  • 判断功能(进行整体匹配)
public boolean matches(String regex)
//要求验证一个手机号,要求必须是以138 139开头的

String content2 = "13821231341";
if(content2.matches("13[89]\\d{8}")){
	System.out.println("是一个手机号");
}
  • 分割功能
public String[] split(String regex)
String content3 = "hello#bob-I2am&lihua";
String[] s = content3.split("#|-|\\d|&");
for (String ss : s) {
	System.out.println(ss);
}
//打印出的结果为:
//hello
//bob
//I
//am
//lihua

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值