正则表达式[总结]

文章目录

    • [1. 为什么要学习正则表达式](#1. 为什么要学习正则表达式)
    • [2. 再提出几个问题?](#2. 再提出几个问题?)
    • [3. 解决之道-正则表达式](#3. 解决之道-正则表达式)
    • [4. 正则表达式基本介绍](#4. 正则表达式基本介绍)
    • [5. 正则表达式底层实现(重要)](#5. 正则表达式底层实现(重要))
    • [6. 正则表达式语法](#6. 正则表达式语法)
      • [6.1 基本介绍](#6.1 基本介绍)
      • [6.2 元字符(Metacharacter)-转义号 \\\](#6.2 元字符(Metacharacter)-转义号 \)
      • [6.3 元字符-字符匹配符](#6.3 元字符-字符匹配符)
      • [6.4 元字符-选择匹配符](#6.4 元字符-选择匹配符)
      • [6.5 元字符-限定符](#6.5 元字符-限定符)
      • [6.6 元字符-定位符](#6.6 元字符-定位符)
      • [6.7 分组](#6.7 分组)
      • [6.8 非贪婪匹配](#6.8 非贪婪匹配)
    • [7. 应用实例](#7. 应用实例)
    • [8. 正则表达式三个常用类](#8. 正则表达式三个常用类)
    • [9. 分组、捕获、反向引用](#9. 分组、捕获、反向引用)
      • [9.1 提出需求](#9.1 提出需求)
      • [9.2 介绍](#9.2 介绍)
      • [9.3 看几个小案例](#9.3 看几个小案例)
      • [9.4 经典的结巴程序](#9.4 经典的结巴程序)
    • [10. String 类中使用正则表达式](#10. String 类中使用正则表达式)
      • [10.1 替换功能](#10.1 替换功能)
      • [10.2 判断功能](#10.2 判断功能)
      • [10.3 分割功能](#10.3 分割功能)

1. 为什么要学习正则表达式

  • 极速体验正则表达式威力
java 复制代码
//1. 先创建一个 Pattern 对象 , 模式对象, 可以理解成就是一个正则表达式对象
//Pattern pattern = Pattern.compile("[a-zA-Z]+");
//Pattern pattern = Pattern.compile("[0-9]+");
//Pattern pattern = Pattern.compile("([0-9]+)|([a-zA-Z]+)");
//Pattern pattern = Pattern.compile("<a target=\"_blank\" title=\"(\\S*)\"");

2. 再提出几个问题?

3. 解决之道-正则表达式

4. 正则表达式基本介绍

5. 正则表达式底层实现(重要)

为让大家对正则表达式底层实现有一个直观的映象,给大家举个实例

给你一段字符串(文本),请找出所有四个数字连在一起的子串, 比如:

应该找到 1998 1999 3443 9889 ===> 分析底层实现 RegTheory.java

java 复制代码
package com.xjz.regexp;

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

/**
 * @author xjz_2002
 * @version 1.0
 * 分析 java 的正则表达式的底层实现(重要)
 */
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. 开始匹配
        /**
         *
         * matcher.find() 完成的任务 (考虑分组)
         * 什么是分组,比如 (\d\d)(\d\d),正则表达式中有() 表示分组,第一个()表示第 1组,第2个()表示第 2组..
         * 1. 根据指定的规则,定位满足规则的子字符串(比如(19)(98))
         * 2. 找到后,将 子字符串的开始的索引记录到 matcher 对象的属性 int[] groups;
         *      2.1 groups[0] = 0,把该子字符串的结束的索引+1 的值记录到 groups[1] = 4
         *      2.2 记录 1组()匹配到的字符串 groups[2] = 0  groups[3] = 2
         *      2.3 记录 2组()匹配到的字符串 groups[4] = 2  groups[5] = 4
         *      2.4 如果有更多的分组..
         * 3. 同时记录 oldLast 的值为 子字符串的结束的 索引 +1 的值 即 35,即下次执行 find时,就从 35 开始匹配
         *
         * matcher.group(0) 分析
         * 源码:
         * 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();
         *  }
         *  1. 根据 groups[0]=31 和 groups[1]=35 的记录的位置,从 content 开始截取子字符串返回
         *      就是 [31,35) 包含 31但是不包含索引为 35 的位置
         *
         *  如果再次指向 find 方法,仍然按上面分析来执行
         */

        while (matcher.find()){
            //小结
            //1. 如果正则表达式有()  即分组
            //2. 取出匹配的字符串规则如下
            //3. group(0) 表示匹配到的子字符串
            //4. group(1) 表示匹配到的子字符串的第一组子串
            //5. group(2) 表示匹配到的子字符串的第二组子串
            //6. ... 但是分组的数不能越界.
            System.out.println("找到" + matcher.group(0));
            System.out.println("第 1 组()匹配到的值=" + matcher.group(1));
            System.out.println("第 2 组()匹配到的值=" + matcher.group(2));

        }

    }
}

6. 正则表达式语法

6.1 基本介绍

6.2 元字符(Metacharacter)-转义号 \\

java 复制代码
package com.xjz.regexp;

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

/**
* @author xjz_2002
* @version 1.0
* 演示转义字符的使用
*/
public class RegExp02 {
   public static void main(String[] args) {
       String content = "abc$(a.bc(123()";
       //匹配( --> \\(
       //匹配. --> \\.
       //String regStr = "\\(";
       //String regStr = "\\.";
       //String regStr = "\\d\\d\\d";
       String regStr = "\\d{3}"; // \\d\\d\\d == \\d{3}
       Pattern pattern = Pattern.compile(regStr);
       Matcher matcher = pattern.matcher(content);

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

6.3 元字符-字符匹配符

java 复制代码
package com.xjz.regexp;

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

/**
 * @author xjz_2002
 * @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));
        }

    }
}

6.4 元字符-选择匹配符

java 复制代码
package com.xjz.regexp;

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

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

        String content = "liyunlong 李 栗子";
        String regStr = "li|李|栗";

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

        while (matcher.find()){
            System.out.println("找到 " + matcher.group(0));
        }
    }
}
  • 运行结果

6.5 元字符-限定符

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

应用案例

java 复制代码
package com.xjz.regexp;

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

/**
 * @author xjz_2002
 * @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 = "a{4,5}";//表示匹配 1111 或者 11111
        //String regStr = "\\d{2,5}";//表示匹配 2位数或者 3,4,5位的数字0-9

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

6.6 元字符-定位符

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

RegExp06.java

java 复制代码
package com.xjz.regexp;

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

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

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

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

        //和\\b的含义刚刚相反[被匹配的字符串最前面,也可以是空掉的字符串的后面]
        String regStr = "xu\\B";

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

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

    }
}

6.7 分组

RegExp07.java

java 复制代码
package com.xjz.regexp;

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

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

        String content = "xujinzhuo s7789 nn1189xu";

        //下面就是非命名分组
        //说明
        // 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"));
        }
    }
}

RegExp08.java

java 复制代码
package com.xjz.regexp;

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

/**
 * @author xjz_2002
 * @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));
        }
    }
}

6.8 非贪婪匹配

?

java 复制代码
package com.xjz.regexp;

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

/**
 * @author xjz_2002
 * @version 1.0
 * 非贪婪匹配 ?
 */
public class RegExp09 {
    public static void main(String[] args) {

        String content = "tom111111jack";

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

}

运行结果

7. 应用实例

java 复制代码
package com.xjz.regexp;

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

/**
 * @author xjz_2002
 * @version 1.0
 * 正则表达式的应用实例
 */
public class RegExp10 {
    public static void main(String[] args) {
        String content = "13588889999";
        //  汉字
        //String regStr = "^[\u0391-\uffe5]+$";

        // 邮政编码
        // 要求:是 1-9 开头的一个六位数. 比如:123890
        //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("不满足格式");
        }

    }
}
java 复制代码
package com.xjz.regexp;

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

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

        String content = "https://www.bilibili.com/video/BV1eu4y1W7PL/?spm_id_from=333.1007.tianma.2-1-4.click&vd_source=c5907cbcddead65ce568e72fc5ad5385";

        /**
         * 思路
         * 1. 先确定 url 的开始部分 https://
         * 2. 然后通过 ([\w-]+\.)+[\w-] 匹配  www.bilibili.com
         *
         */

        //多写多练,多总结
        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));//
    }
}

8. 正则表达式三个常用类

java 复制代码
package com.xjz.regexp;

import java.util.regex.Pattern;

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

    public static void main(String[] args) {
        String content = "hello world 雪豹";
//        String regStr = "hello";
        String regStr = "hello.*";

        boolean matches = Pattern.matches(regStr, content);
        System.out.println("整体匹配=" + matches);
    }
}
java 复制代码
package com.xjz.regexp;

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

/**
 * @author xjz_2002
 * @version 1.0
 * Matcher 类的常用方法
 */
public class MatcherMethod {
    public static void main(String[] args) {
        String content = "hello edu jack xjz2002 hello smith hello xjz2002 xjz2002";
        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 有 xjz2002 替换成 老鼠爱大米
        regStr = "xjz2002";
        pattern = Pattern.compile(regStr);
        matcher = pattern.matcher(content);
        //注意: 返回的字符串才是替换后的字符串 原来的 content 不变化
        String newContent = matcher.replaceAll("老鼠爱大米");
        System.out.println("newContent=" + newContent);
        System.out.println("content=" + content);
    }
}

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

9.1 提出需求

9.2 介绍

9.3 看几个小案例

9.4 经典的结巴程序

java 复制代码
package com.xjz.regexp;

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

/**
 * @author xjz_2002
 * @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+");
//        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);
    }

}

10. String 类中使用正则表达式

10.1 替换功能

String 类 public String replaceAll(String regex,String replacement)

10.2 判断功能

String 类 public boolean matches(String regex){} **//**使用 Pattern Matcher

10.3 分割功能

String 类 public String[] split(String regex)

StringReg.java 代码如下:

java 复制代码
package com.xjz.regexp;

/**
 * @author xjz_2002
 * @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 = "13888899999";
        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 小时前
正则表达式优化之算法和效率优化
前端·javascript·算法·正则表达式
Java编程乐园12 小时前
Java中以某字符串开头且忽略大小写字母如何实现【正则表达式(Regex)】
java·正则表达式
好学近乎知o15 小时前
正则表达式(学习Django过程中可能涉及的)
学习·正则表达式·django
SunnyRivers2 天前
基础爬虫案例实战
正则表达式·爬虫实战·多进程·requests
西洼工作室3 天前
【java 正则表达式 笔记】
java·笔记·正则表达式
kiss strong4 天前
正则表达式
正则表达式
Linux运维技术栈4 天前
Python字符串及正则表达式(十一):正则表达式、使用re模块实现正则表达式操作
开发语言·python·正则表达式
jackiendsc4 天前
Java中正则表达式的介绍、使用场景及示例代码
java·开发语言·正则表达式
taller_20004 天前
VBA之正则表达式(48)-- 快速拆分中文语句
正则表达式·正则·拆分中文·中文拆分·中文标点
梧桐树04294 天前
python:正则表达式
数据库·python·正则表达式