当前位置:首页>笔记分享>Java笔记>正则表达式(Java)

正则表达式(Java)

1.正则表达式是什么

在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。

2.正则的底层实现

  • 创建模式对象[即正则表达式对象]
Pattern pattern = Pattern.compile("正则表达式");
  • 创建匹配器
//创建匹配器 matcher, 按照 正则表达式的规则 去匹配 content 字符串
Matcher matcher = pattern.matcher("需要匹配的文本");
  • matcher的方法
matcher.find(); //找到匹配的分组
matcher.group(int index)//获取分组

使用实例

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

/**
 * ClassName: RegTheory
 * Description:
 * date: 2022/9/30 22:42
 *
 * @author gongjunpeng
 * @since JDK 17
 */
public class RegTheory {
    public static void main(String[] args) {
        String content = "1998 年 12 月 8 日,第二代 Java 平台的企业版 J2EE 发布。1999 年 6 月,Sun 公司发布了" +
                "第二代 Java 平台(简称为 Java2)的 3 个版本:J2ME(Java2 Micro Edition,Java2 平台的微型" +
                "版),应用于移动、无线及有限资源的环境;J2SE(Java 2 Standard Edition,Java 2 平台的" +
                "标准版),应用于桌面环境;J2EE(Java 2Enterprise Edition,Java 2 平台的企业版),应" +
                "用 3443 于基于 Java 的应用服务器。Java 2 平台的发布,是 Java 发展过程中最重要的一个" +
                "里程碑,标志着 Java 的应用开始普及 9889 ";
        //目标:匹配所有四个数字
        // 说明
        // 1. \\d 表示一个任意的数字
        String regStr = "(\\d\\d)(\\d\\d)";
        // 2. 创建模式对象[即正则表达式对象]
        Pattern pattern = Pattern.compile(regStr);
        // 3. 创建匹配器
        // 说明:创建匹配器 matcher, 按照 正则表达式的规则 去匹配 content 字符串
        Matcher matcher = pattern.matcher(content);
        // 4.开始匹配
        while (matcher.find()) {
            //小结
            // 1. 如果正则表达式有() 即分组
            // 2. 取出匹配的字符串规则如下
            // 3. group(0) 表示匹配到的子字符串
            // 4. group(1) 表示匹配到的子字符串的第一组字串
            // 5. group(2) 表示匹配到的子字符串的第 2 组字串
            // 6. ... 但是分组的数不能越界.
            System.out.println("找到: " + matcher.group(0));
            System.out.println("第 1 组()匹配到的值=" + matcher.group(1));
            System.out.println("第 2 组()匹配到的值=" + matcher.group(2));
        }
    }
}

2.1 find()方法原理

源码

public boolean find() {
        int nextSearchIndex = last;
        if (nextSearchIndex == first)
            nextSearchIndex++;

        // If next search starts before region, start it at region
        if (nextSearchIndex < from)
            nextSearchIndex = from;

        // If next search starts beyond region then it fails
        if (nextSearchIndex > to) {
            for (int i = 0; i < groups.length; i++)
                groups[i] = -1;
            return false;
        }
        return search(nextSearchIndex);
    }

先说说分组是什么

用小括号括起来即为一组比如 (\d\d)(\d\d)

正则表达式中有() 表示分组,第1个()表示第1组,第2个()表示第2组...

配合上面使用实例看

  1. 根据指定的规则 ,定位满足规则的子字符串(比如(19)(98))

  2. 找到后,将子字符串的开始的索引记录到 matcher 对象的属性 int[] groups;

    • groups[0] = 0 , 把该子字符串的结束的索引+1 的值记录到 groups[1] = 4
    • 记录第一组()匹配到的字符串 groups[2] = 0 groups[3] = 2
    • 记录第二组()匹配到的字符串 groups[4] = 2 groups[5] = 4
    • 如果有更多的分组.....
  3. 同时记录 oldLast 的值为 子字符串的结束的 索引+1 的值即 4, 即下次执行 find() 时,就从 4 开始匹配

如果没有分组则只会占用groups[0]和groups[1]来存放满足字符串的下标

image-20220930233548792

2.2 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();
    }

可以看出来返回的就是根据find的groups数组的下标来截取的子串

比如group(0)就是获取匹配到的子串

group(1)就是获取第一个分组(前提是要分组了)

3.元字符

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

限定符 选择匹配符 分组组合和反向引用符 特殊字符 字符匹配符 定位符

首先说下转移符号\\

说明:在我们使用正则表达式取检索某些特殊字符的时候,需要用到转移符号,负责检索不到结果,甚至会报错。

比如匹配“abc(”中的“”或者“(”如果不使用转移符号就会报错

String regstr = "\\("

下面只是比较常用的,用得不多的建议用的时候查阅百度

3.1 字符匹配符

符号 文字描述 示例 解释
[] 可接收的字符列表 [abc] a、b、c中的任意一个字符
[^] 不可接收的字符列表 [^abc] 除a、b、c中的任意一个字符包含数字和特殊字符
- 连字符 A-Z 任意单个大写字母
. 匹配除\n以外的任何字符 a..b 以a开头b结尾中间包含两个任意字符的长度为4的字符串,如a12b
\\d 匹配单个数字字符 \\d{3}(\\d)? 包含三个或者四个数字的字符串,如123,1234
\\D 匹配单个非数字字符相当于[^0-9] \\D(\\d)* 非数字开头,后续接任意个数字,如a、a123
\\w 匹配单个数字、大小写字母下划线,相当于[0-9a-zA-Z_] \\d{3}\\w{4} 以三个数字开头的长度为7的数字字母字符串,如123a12b
\\W 匹配单个非数字、大小写字母和下划线的字符,相当于[^0-9a-zA-Z_] \\W+\\d{2} 以至少1个非数字字母开头,2个数字字符结尾的字符串,比如#29,#?12
\\s 匹配任意空白字符串,空格制表符等等
\\S 匹配非任意空白字符串,空格制表符等等和\\s相反
. 匹配出\n之外的所有字符,如果要匹配则需要使用\\. \\.

“?”号代表0或1 表示可有可无

“*”号代表任意个(可以为0个)

“+”号代表1个或者多个

"{int}" 代表匹配个数 \\d\\d\\d=\\d{3}

匹配字符串如何不区分大小写

  • 字符串前加"(?i)"
  • 或者创建正则的时候设置不区分大小写

Pattern pattern = Pattern.compile(regStr, Pattern.CASE_INSENSITIVE);

String regStr = "abc"; //区分大小写
String regStr = "(?i)abc"; //abc都不不区分大小写
String regStr = "a(?i)bc"; //只有bc都不不区分大小写
String regStr = "a((?i)b)c"; //只有b不不区分大小写

具体的使用看代码

package com.gong.regexp;

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

/**
 * @author xiaopeng
 * @version 1.0
 * 演示字符匹配符 的使用
 */
public class RegExp03 {
    public static void main(String[] args) {

        String content = "a11c8abc _ABCy @";
        //String regStr = "[a-z]";//匹配 a-z之间任意一个字符
        //String regStr = "[A-Z]";//匹配 A-Z之间任意一个字符
        //String regStr = "abc";//匹配 abc 字符串[默认区分大小写]
        //String regStr = "(?i)abc";//匹配 abc 字符串[不区分大小写]
        //String regStr = "[0-9]";//匹配 0-9 之间任意一个字符
        //String regStr = "[^a-z]";//匹配 不在 a-z之间任意一个字符
        //String regStr = "[^0-9]";//匹配 不在 0-9之间任意一个字符
        //String regStr = "[abcd]";//匹配 在 abcd中任意一个字符
        //String regStr = "\\D";//匹配 不在 0-9的任意一个字符
        //String regStr = "\\w";//匹配 大小写英文字母, 数字,下划线
        //String regStr = "\\W";//匹配 等价于 [^a-zA-Z0-9_]
        //\\s 匹配任何空白字符(空格,制表符等)
        //String regStr = "\\s";
        //\\S 匹配任何非空白字符 ,和\\s刚好相反
        //String regStr = "\\S";
        //.  匹配出 \n 之外的所有字符,如果要匹配.本身则需要使用 \\.
        String regStr = ".";

        //说明
        //1. 当创建Pattern对象时,指定 Pattern.CASE_INSENSITIVE, 表示匹配是不区分字母大小写.
        Pattern pattern = Pattern.compile(regStr/*, Pattern.CASE_INSENSITIVE*/);
        Matcher matcher = pattern.matcher(content);

        while (matcher.find()) {
            System.out.println("找到 " + matcher.group(0));
        }
    }
}

3.2选择匹配符

符号 符号 示例 解释
| 匹配”|“之前或之后的表达式 ab|cd 匹配出ab或cd
package com.gong.regexp;

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

/**
 * @author xiaopeng
 * @version 1.0
 * 选择匹配符
 */
public class RegExp04 {
    public static void main(String[] args) {

        String content = "xiaopeng 鹏 朋友";
        String regStr = "peng|鹏|朋";

        Pattern pattern = Pattern.compile(regStr/*, Pattern.CASE_INSENSITIVE*/);
        Matcher matcher = pattern.matcher(content);

        while (matcher.find()) {
            System.out.println("找到 " + matcher.group(0));
        }
    }
}

3.3 限定符

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

符号 含义 示例 说明 匹配输入
* 指定字符重复0次或n次,0~多 (abc)* 仅包含人一个abc的字符串 abc、abcabc
+ 指定字符重复1次或n次,1~多 m+(abc)* 以至少一个m开头,后面接任意个abc子串 m、mabc
指定字符重复0次或1次,0或1 m+abc? 以至少一个m开头,后面接ab或者abc mabc、mmab
{n} 只能输入n个字符 [abcd]{3} 由abcd任意组成的长度为3的字符串 abc、bda
{n,} 指定至少匹配n个字符 [abcd]{3,} 由abcd任意组成的长度不小于3的字符串 abc、abbc、abbccddd
{n,m} 指定匹配至少n个但不多于m个字符 [abcd]{3,5} 由abcd任意组成的长度大于等于3小于等于5的的字符串 abc、abcd、abcda

{n,m} java是贪婪匹配尽可能匹配多得

比如有个文本是1111aaaa 正则是a{3,4}匹配出来就是aaaa

记住java正则是贪婪匹配

演示限定符的使用

package com.gong.regexp;

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

/**
 * @author xiaopeng
 * @version 1.0
 * 演示限定符的使用
 */
public class RegExp05 {
    public static void main(String[] args) {
        String content = "a211111aaaaaahello";

        //a{3},1{4},\\d{2}
        //String regStr = "a{3}";// 表示匹配 aaa
        //String regStr = "1{4}";// 表示匹配 1111
        //String regStr = "\\d{2}";// 表示匹配 两位的任意数字字符

        //a{3,4},1{4,5},\\d{2,5}

        //细节:java匹配默认贪婪匹配,即尽可能匹配多的
        //String regStr = "a{3,4}"; //表示匹配 aaa 或者 aaaa
        //String regStr = "1{4,5}"; //表示匹配 1111 或者 11111
        //String regStr = "\\d{2,5}"; //匹配2位数或者3,4,5

        //1+
        //String regStr = "1+"; //匹配一个1或者多个1
        //String regStr = "\\d+"; //匹配一个数字或者多个数字

        //1*
        //String regStr = "1*"; //匹配0个1或者多个1

        //演示?的使用, 遵守贪婪匹配
        String regStr = "a1?"; //匹配 a 或者 a1
        Pattern pattern = Pattern.compile(regStr/*, Pattern.CASE_INSENSITIVE*/);
        Matcher matcher = pattern.matcher(content);

        while (matcher.find()) {
            System.out.println("找到 " + matcher.group(0));
        }
    }
}

3.4 定位符

定位符:规定要匹配的字符串出现的位置,比如在字符串的开始还是在结束的位置,这个也是相当有用的必须掌握

符号 含义 示例 说明 匹配输入
^ 指定起始字符 ^[0-9]+[a-z]* 至少一个数字开头后面加任意个小写字母 123、6aa、555def
$ 指定结束字符 ^[0-9]\\-[a-z]+$ 以一个数字开头加上“-”是再加上1-n个小写字母结束 1-a、2-abc
\\b 匹配目标字符串边界 gong\\b 这里说的字符串的边界指的是子串间空格,或者目标字符串的结束位置(字符串结尾或者空格分割的子串) gongjungong nngong
\\B 匹配目标字符串的非边界 gong\\B 和\\b的含义刚刚相反 gongjungong nngong

演示

package com.gong.regexp;

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

/**
 * @author xiaopeng
 * @version 1.0
 * 演示定位符的使用
 */
public class RegExp06 {
    public static void main(String[] args) {

        String content = "hanshunping sphan nnhan";
        //String content = "123-abc";
        //以至少1个数字开头,后接任意个小写字母的字符串
        //String regStr = "^[0-9]+[a-z]*";
        //以至少1个数字开头, 必须以至少一个小写字母结束
        //String regStr = "^[0-9]+\\-[a-z]+$";

        //表示匹配边界的han[这里的边界是指:被匹配的字符串最后,
        // 也可以是空格的子字符串的后面]
        //String regStr = "han\\b";

        //和\\b的含义刚刚相反
        String regStr = "han\\B";

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);

        while (matcher.find()) {
            System.out.println("找到=" + matcher.group(0));
        }

    }
}

3.5 分组组合

3.5.1 捕获分组

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

非分组通过matcher.group(0)获取匹配到的字符串

分组通过matcher.group(0)获取匹配到的字符串,matcher.group(n)取到第n个分组,n不能超过分组数,命名分组还可以通过组名来获取matcher.group('name')

代码演示

package com.gong.regexp;

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

/**
 * @author xiaopeng
 * @version 1.0
 * 分组:
 */
public class RegExp07 {
    public static void main(String[] args) {

        String content = "hanshunping s7789 nn1189han";

        //下面就是非命名分组
        //说明
        // 1. matcher.group(0) 得到匹配到的字符串
        // 2. matcher.group(1) 得到匹配到的字符串的第1个分组内容
        // 3. matcher.group(2) 得到匹配到的字符串的第2个分组内容

        //String regStr = "(\\d\\d)(\\d\\d)";//匹配4个数字的字符串

        //命名分组: 即可以给分组取名
        String regStr = "(?<g1>\\d\\d)(?<g2>\\d\\d)";//匹配4个数字的字符串

        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("第1个分组内容[通过组名]=" + matcher.group("g1"));
            System.out.println("第2个分组内容=" + matcher.group(2));
            System.out.println("第2个分组内容[通过组名]=" + matcher.group("g2"));

        }
    }
}

3.5.2 非捕获分组

特别分组

非捕获分组不能用group(1)来捕获,因为没有分组

常用分组构造形式 说明 示例
(?:pattern) 匹配pattern但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储以后使用的匹配。这对于用“or”字符(|)组合模式部件的情况很有用。 ‘industr(?:y|ies)’是比‘industry|industries’更经济的表达式
(?=pattern) 它是一个非捕获匹配。 例如,‘Windows (?=95|98|NT|2000)’匹配‘Windows 2000’中的‘Windows’,但不匹配‘Windows 3.1’中的‘Windows’
(?!pattern) 该表达式匹配不处于匹配pattern的字符串的起始点的搜索字符串。它是一个非捕获匹配。 例如,‘Windows (?!95|98|NT|2000)'匹配‘Windows 3.1’中的‘Windows’,而不匹配‘Windows 2000’中的‘Windows’

演示代码

package com.gong.regexp;

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

/**
 * @author xiaopeng
 * @version 1.0
 * 演示非捕获分组, 语法比较奇怪
 */
public class RegExp08 {
    public static void main(String[] args) {

        String content = "hello龚昊教育 jack龚昊老师 龚昊同学hello龚昊学生";

//        找到 龚昊教育 、龚昊老师、龚昊同学 子字符串
        //String regStr = "龚昊教育|龚昊老师|龚昊同学";
        //上面的写法可以等价非捕获分组, 注意:不能 matcher.group(1)
        //String regStr = "龚昊(?:教育|老师|同学)";

        //找到 龚昊 这个关键字,但是要求只是查找龚昊教育和 龚昊老师 中包含有的龚昊
        //下面也是非捕获分组,不能使用 matcher.group(1)
        //String regStr = "龚昊(?=教育|老师)";

        //找到 龚昊 这个关键字,但是要求只是查找 不是 (龚昊教育 和 龚昊老师) 中包含有的龚昊
        //下面也是非捕获分组,不能使用 matcher.group(1)
        String regStr = "龚昊(?!教育|老师)";

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("找到: " + matcher.group(0));
        }
    }
}

3.6 非贪婪匹配

java默认是贪婪匹配(尽可能多匹配),我们如果想要非贪婪匹配就需要在表达式后面加一个限定符?问号

演示代码

package com.gong.regexp;

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

/**
 * @author xiaopeng
 * @version 1.0
 * 非贪婪匹配
 */
public class RegExp09 {
    public static void main(String[] args) {
        String content = "hello111111 ok";
        //String regStr = "\\d+"; //默认是贪婪匹配
       // String regStr = "\\d+?"; //非贪婪匹配
        String regStr = "\\d+?"; //非贪婪匹配

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("找到: " + matcher.group(0));
        }
    }
}

3.7.应用实例

3.7.1 简单的验证

  • 汉字

  • 邮政编码

    • 要求是1-9开头的一个六位数字,比如123890
  • QQ号码

    • 要求:是1-9开头的一个5-10位的数字 比如:334405060 444467
  • 手机号码

    • 要求:必须以13,14,15,18开头的11位数字 比如15555585015

代码演示

package com.gong.regexp;

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

/**
 * @author xiaopeng
 * @version 1.0
 * 正则表达式的应用实例
 */
public class RegExp10 {
    public static void main(String[] args) {
        String content = "13588889999";
        // 汉字
        //String regStr = "^[\u0391-\uffe5]+";
        // 邮政编码
        // 要求:1.是1-9开头的一个六位数.  比如:123890
        //      2.
        //      3.
        //String regStr = "^[1-9]\\d{5}";
        // QQ号码
        // 要求:  是1-9开头的一个(5位数-10位数)  比如:  12389 , 1345687 , 187698765
        //String regStr = "^[1-9]\\d{4,9}";

        // 手机号码
        // 要求: 必须以13,14,15,18 开头的11位数 , 比如 13588889999
        String regStr = "^1[3|4|5|8]\\d{9}";

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

    }
}

3.7.2 较复杂的验证

URL验证

代码演示

注意:[. ? *]表示匹配就是.本身

中括号中的符号就代表符号本身

package com.gong.regexp;

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

/**
 * @author xiaopeng
 * @version 1.0
 * 演示正则表达式的使用
 */
public class RegExp11 {
    public static void main(String[] args) {

        //String content = "https://www.bilibili.com/video/BV1fh411y7R8?from=search&seid=1831060912083761326";
        String content = "http://edu.3dsmax.tech/yg/bilibili/my6652/pc/qg/05-51/index.html#201211-1?track_id=jMc0jn-hm-yHrNfVad37YdhOUh41XYmjlss9zocM26gspY5ArwWuxb4wYWpmh2Q7GzR7doU0wLkViEhUlO1qNtukyAgake2jG1bTd23lR57XzV83E9bAXWkStcAh4j9Dz7a87ThGlqgdCZ2zpQy33a0SVNMfmJLSNnDzJ71TU68Rc-3PKE7VA3kYzjk4RrKU";

        /**
         * 思路
         * 1. 先确定 url 的开始部分 https:// | http://(可有可无根据要求)
         * 2.然后通过 ([\w-]+\.)+[\w-]+ 匹配 www.bilibili.com
         * 3. /video/BV1fh411y7R8?from=sear 匹配(\/[\w-?=&/%.#]*)?
         */
        String regStr = "^((http|https)://)?([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%.#]*)?$";//注意:[. ? *]表示匹配就是.本身

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

        //这里如果使用Pattern的matches 整体匹配 比较简洁
        System.out.println(Pattern.matches(regStr, content));//

    }
}

4.正则表达式常用类

java.util.regex包主要包括一下三个类Pattern类、Matcher类和PatternSynaxException类

4.1 Pattern类

单词的意思是模式

pattern对象是一个正则表达式对象,Pattern类没有公共构造方法。要创建一个Pattern对象,调用其公共静态方法,他返回一个Pattern对象。该方法接收一个正则表达式作为它的第一个参数。

比如

Pattern pattern = Pattern.compile(pattern);

常用方法

Pattern.matches("表达式","内容") 整个是整体匹配

只是匹配不返回匹配的内容

自带起始终止符号^$

看maches方法的源码

public static boolean matches(String regex, CharSequence input) {
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(input);
        return m.matches();
    }

我们看到底层还是Pattern.compile(regex);最后返回还是调用Matcher的matches方法

演示代码

package com.gong.regexp;

import java.util.regex.Pattern;

/**
 * @author xiaopeng
 * @version 1.0
 * 演示matches方法,用于整体匹配, 在验证输入的字符串是否满足条件使用
 */
public class PatternMethod {

    public static void main(String[] args) {
        String content = "hello abc hello, 123";
        //String regStr = "hello";
        String regStr = "hello.*";

        boolean matches = Pattern.matches(regStr, content);
        System.out.println("整体匹配= " + matches);
    }
}

4.2 Matcher类

单词的意思是匹配器

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

方法 说明
public int start () 返回以前的初始索引
public int start (int group) 返回在以前的匹配操作期间,由给定组所捕获的子序列的初始索引
public int end () 返回最后匹配字符之后的偏移量
public int end (int group) 返回在以前的匹配操作期间,由给定组所捕获的子序列的最后字符之后的偏移量
public booleanlookingAt () 尝试将从区域开头开始的输入序列与该模式匹配
public boolean find() 尝试查找与该模式匹配的输入序列的下一个子序列
public boolean find(int start) 重置此匹配器,然后尝试查找匹配该模式,从指定索引开始的输入序列的下一个子序列
public boolean matches() 尝试将整个区域与模式匹配
public Matcher appendReplacement(StringBuffer sb,String replacement) 实现非终端添加和替换操作
public StringBuffer appendTail(StringBuffer sb) 实现终端添加和替换步骤
public String replaceAll(String replacement) 替换匹配到的字符串
public String replaceFirst(String replacement) 替换匹配到的第一个字符串
public static String quoteReplacement(String s) 返回指定字符串的字面替换字符串,这个方法返回一个字符串,就像传递给Matcher类的appendReplacement方法一个字面字符串一样工作

演示代码

package com.gong.regexp;

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

/**
 * @author xiaopeng
 * @version 1.0
 * Matcher 类的常用方法
 */
public class MatcherMethod {
    public static void main(String[] args) {
        String content = "hello edu jack xpedutom hello smith hello xpedu xpedu";
        String regStr = "hello";

        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()));
        }

        //整体匹配方法,常用于,去校验某个字符串是否满足某个规则
        System.out.println("整体匹配=" + matcher.matches());

        //完成如果content 有 xpedu 替换成 龚昊教育
        regStr = "xpedu";
        pattern = Pattern.compile(regStr);
        matcher = pattern.matcher(content);
        //注意:返回的字符串才是替换后的字符串 原来的 content 不变化
        String newContent = matcher.replaceAll("龚昊教育");
        System.out.println("newContent=" + newContent);
        System.out.println("content=" + content);

    }
}

4.3 PatternSynaxException类

PatternSynaxException是一个非强制异常类,它表示一个正则表达式模式中的语法错误

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

5.1 反向引用

先看下面问题

给你一段文本,请你找出所有四个数字连在一起的子串,并且这四个数字要满足

  • 第1位与第4位相同
  • 第2位与第3位相同
  • 比如1221,5775

这个问题通过我们上面学的不好解决

要解决前面的问题,我们需要了解正则表达式的几个概念

  • 分组
    我们可以用圆括号组成一个比较复杂的匹配模式,那么一个圆括号的部分我们可以看作是一个子表达式或一个分组。
  • 捕获
    把正则表达式中子表达式或分组匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用,从左向右, 以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。组0代表的是整个正则式
  • 反向引用
    圆括号的内容被捕获后,可以在这个括号后被使用,从而写出一个比较实用的匹配模式,这个我们称为反向引用,这种引用既可以是在正则表达式内部,也可以是在正则表达式外部, 内部反向引用\\分组号,外部反向引用$分组号

分组和捕获前面说过了,下面举例反向引用的小例子

(一)要匹配连续两个相同的数字:(\\dd)\\1

(二)要匹配连续五个相同的数字:(\\d)\\1{4}

(三)要匹配个位与千位相同十位与百位相同的数5665:(\\d)(\\d)\\2\\1

(四)在字符串中检索商品编号,形式如:12332-231132321这样的号码,要求5位数加-加九位数,九位数连续的三位都要一样

代码

package com.gong.regexp;

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

/**
 * @author xiaopeng
 * @version 1.0
 * 反向引用
 */
public class RegExp12 {
    public static void main(String[] args) {

        String content = "h1234el9876lo33333 j12324-333999111a1551ck14 tom11 jack22 yyy12345 xxx";
        //要匹配两个连续的相同数字 :  (\\d)\\1
        //String regStr = "(\\d)\\1";
        //要匹配五个连续的相同数字: (\\d)\\1{4}
        //String regStr = "(\\d)\\1{4}";
        //要匹配个位与千位相同,十位与百位相同的数 5225 , 1551  (\\d)(\\d)\\2\\1
        //String regStr = "(\\d)(\\d)\\2\\1";

        /**
         * 请在字符串中检索商品编号,形式如:12321-333999111 这样的号码,
         * 要求满足前面是一个五位数,然后一个-号,然后是一个九位数,连续的每三位要相同
         */
        String regStr = "\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}";
        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("找到 " + matcher.group(0));
        }
    }
}

5.2 使用案例

5.2.1 结巴去重

package com.gong.regexp;

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

/**
 * @author xiaopeng
 * @version 1.0
 */
public class RegExp13 {
    public static void main(String[] args) {
        String content = "我....我要....学学学学....编程java!";

        //1. 去掉所有的.

        Pattern pattern = Pattern.compile("\\.");
        Matcher matcher = pattern.matcher(content);
        content = matcher.replaceAll("");

 //       System.out.println("content=" + content);

        //2. 去掉重复的字  我我要学学学学编程java!
        // 思路
        //(1) 使用 (.)\\1+
        //(2) 使用 反向引用1 来替换匹配到的内容
        // 注意:因为正则表达式变化,所以需要重置 matcher
//        pattern = Pattern.compile("(.)\\1+");//分组的捕获内容记录到1
//        matcher = pattern.matcher(content);
//        while (matcher.find()) {
//            System.out.println("找到=" + matcher.group(0));
//        }
//
//        //使用 反向引用1 来替换匹配到的内容
//        content = matcher.replaceAll("1");
//        System.out.println("content=" + content);

        //3. 使用一条语句 去掉重复的字  我我要学学学学编程java!
        content = Pattern.compile("(.)\\1+").matcher(content).replaceAll("$1");

        System.out.println("content=" + content);

    }
}

5.2.1 字符串替换分割匹配

Java的String和replace是支持正则表达式的

替换功能

将下面文本的JDK1.3和JDK1.4都换成JDK

判断功能

要求验证一个手机号必须是138或者139开头

分割功能

要求按照#或者-数字等符号来分割,多个符号分割

代码

package com.gong.regexp;

/**
 * @author xiaopeng
 * @version 1.0
 */
public class StringReg {

    public static void main(String[] args) {
        String content = "2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布,几周后其" +
                "获得了Apple公司Mac OS X的工业标准的支持。2001年9月24日,J2EE1.3发" +
                "布。" +
                "2002年2月26日,J2SE1.4发布。自此Java的计算能力有了大幅提升";

        //使用正则表达式方式,将 JDK1.3 和 JDK1.4 替换成JDK
        content = content.replaceAll("JDK1\\.3|JDK1\\.4", "JDK");
        System.out.println(content);

        //要求 验证一个 手机号, 要求必须是以138 139 开头的
        content = "13888889999";
        if (content.matches("1(38|39)\\d{8}")) {
            System.out.println("验证成功");
        } else {
            System.out.println("验证失败");
        }

        //要求按照 # 或者 - 或者 ~ 或者 数字 来分割
        System.out.println("===================");
        content = "hello#abc-jack12smith~北京";
        String[] split = content.split("#|-|~|\\d+");
        for (String s : split) {
            System.out.println(s);
        }

    }
}

6.练习

6.1 验证电子邮箱

邮箱规则

  • 只能一个@
  • @前面是用户名,只能是数字字母和下划线以及”-“
  • @后面是域名,并且域名只能是英文域名,比如souhu.com,qq.com.cn
  • 写出相应的正则表达式,验证输入的字符串是否为满足规则
package com.gong.regexp;

/**
 * @author xiaopeng
 * @version 1.0
 */
public class Homework01 {
    public static void main(String[] args) {
        //规定电子邮件规则为
        //只能有一个@
        //@前面是用户名,可以是a-z A-Z 0-9 _-字符
        //@后面是域名,并且域名只能是英文字母, 比如 sohu.com 或者 tsinghua.org.cn
        //        写出对应的正则表达式, 验证输入的字符串是否为满足规则

        String content = "hsp@tsinghua.org.cn kkk";
        String regStr = "^[\\w-]+@([a-zA-Z]+\\.)+[a-zA-Z]+$";

        //老师说明
        //1. String 的 matches 是整体匹配
        //2. 看看这个matches 底层
        /**
         * String 的 matches
         *  public boolean matches(String regex) {
         *         return Pattern.matches(regex, this);
         *     }
         *
         *  Pattern
         *  public static boolean matches(String regex, CharSequence input) {
         *         Pattern p = Pattern.compile(regex);
         *         Matcher m = p.matcher(input);
         *         return m.matches();
         *     }
         *
         *  Mather类 match
         *  Attempts to match the entire region against the pattern
         *  public boolean matches() {
         *         return match(from, ENDANCHOR);
         *     }
         */
        if (content.matches(regStr)) {
            System.out.println("匹配成功");
        } else {
            System.out.println("匹配失败");
        }

    }
}

6.2 要求验证是不是整数或者小数

提示:区分正负

比如:123,-345,34.89,-0.01

package com.gong.regexp;

/**
 * @author xiaopeng
 * @version 1.0
 */
public class Homework02 {

    public static void main(String[] args) {
        //要求验证是不是整数或者小数
        //提示: 这个题要考虑正数和负数
        //比如: 123 -345 34.89 -87.9 -0.01 0.45 等
        /**
         * 老师的思路
         * 1. 先写出简单的正则表达式
         * 2. 在逐步的完善[根据各种情况来完善]
         */
        String content = "-0.89"; //
        String regStr = "^[-+]?([1-9]\\d*|0)(\\.\\d+)?$";

        if(content.matches(regStr)) {
            System.out.println("匹配成功 是整数或者小数");
        } else {
            System.out.println("匹配失败");
        }
    }
}

6.3 解析URL

http://www.sohu.com:8080/abc/index.htm

(1)协议是什么 http

(2)域名是什么 www.souhu.com

(3)端口是什么 8080

(4)文件名是什么 index.htm

代码

package com.gong.regexp;

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

/**
 * @author xiaopeng
 * @version 1.0
 */
public class Homework03 {
    public static void main(String[] args) {

        String content = "http://www.sohu.com:8080/abc/xxx/yyy/////inde@#%x.htm";

        //因为正则表达式是根据要求来编写的,所以,如果需求需要的话,可以改进.
        String regStr = "^([a-zA-Z]+)://([a-zA-Z.]+):(\\d+)[\\w-/]*/([\\w.@#%]+)$";

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);

        if(matcher.matches()) {//整体匹配, 如果匹配成功,可以通过group(x), 获取对应分组的内容
            System.out.println("整体匹配=" + matcher.group(0));
            System.out.println("协议: " + matcher.group(1));
            System.out.println("域名: " + matcher.group(2));
            System.out.println("端口: " + matcher.group(3));
            System.out.println("文件: " + matcher.group(4));
        } else {
            System.out.println("没有匹配成功");

        }

    }
}

给TA打赏
共{{data.count}}人
人已打赏
Java笔记

SpringBoot

2022-3-8 0:33:50

JavaGUIJava笔记

Java——GUI

2021-9-12 0:22:52

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
购物车
优惠劵
有新私信 私信列表
搜索