自学内容网 自学内容网

Java技术复习提升 20正则表达式

第20章 正则表达式

20.1 为什么要学习正则表达式

package com.fsl.regexp;

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

public class Regexp {
    public static void main(String[] args) {
        String content="在这个数字化的时代,数据无处不在。例如一份项目报告:“项目 X 的进展报告,截止到 2023 年 10 月,已经完成了 75% 的工作量。其中,A 模块的编码工作(主要由程序员 Tom 负责)已经顺利结束。下一步是进行 B 模块的测试工作,预计需要 15 天。此次项目的成功对于公司开拓市场至关重要,它将帮助我们在 @#$% 行业中占据更有利的地位。我们要确保每一个细节都不出错,包括数据的准确性、代码的规范性等,避免出现像之前项目中的 *&^ 错误。”";
        // 正则表达式技术 
        //1. 先创建一个Pattern对象 , 模式对象, 可以理解成就是一个正则表达式对象
        Pattern pattern1=Pattern.compile("[a-zA-Z]+");
        Pattern pattern2=Pattern.compile("[0-9]+");
        Pattern pattern3=Pattern.compile("[\\u4e00-\\u9fff]+");
        Pattern pattern4=Pattern.compile("[。,;:?!@#$%*&^()]+");
        //2. 创建一个匹配器对象 
        //理解: 就是 matcher 匹配器按照 pattern(模式/样式), 到 content 文本中去匹配         //找到就返回true, 否则就返回false
        Matcher matcher=pattern4.matcher(content);
        int no=0;
        while(matcher.find()){
            System.out.println("find:"+" "+(++no)+" "+matcher.group(0));
        }
    }
}

 

 

 

 

20.2 正则表达式

 

 基本介绍

20.3 正则表达式底层实现

 

package com.fsl.regexp;

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

public class Regexp {
    public static void main(String[] args) {
        String content="在这个数字化的时代,数据无处不在。例如一份项目报告:“项目 X 的进展报告,截止到 2023 年 10 月,已经完成了 75% 的工作量。其中,A 模块的编码工作(主要由程序员 Tom 负责)已经顺利结束。下一步是进行 B 模块的测试工作,预计需要 15 天。此次项目的成功对于公司开拓市场至关重要,它将帮助我们在 @#$% 行业中占据更有利的地位。我们要确保每一个细节都不出错,包括数据的准确性、代码的规范性等,避免出现像之前项目中的 *&^ 错误。”";

        Pattern pattern1=Pattern.compile("[a-zA-Z]+");
        Pattern pattern2=Pattern.compile("[0-9]+");
        Pattern pattern3=Pattern.compile("[\\u4e00-\\u9fff]+");
        Pattern pattern4=Pattern.compile("[。,;:?!@#$%*&^()]+");
        Pattern pattern5=Pattern.compile("(\\d\\d)(\\d\\d)");

        Matcher matcher=pattern5.matcher(content);
        int no=0;
        while(matcher.find()){
            System.out.println("find:"+" "+(++no)+" "+matcher.group(0));//为匹配到的每个文本的完整内容
            System.out.println("find:"+" "+(++no)+" "+matcher.group(1));//为匹配到的每个文本的第一个()捕获组捕获到的内容
            System.out.println("find:"+" "+(++no)+" "+matcher.group(2));//为匹配到的每个文本的第二个()捕获组捕获到的内容
        }
    }
}

 

 

 20.4 正则表达式语法

 转义符:\\

package com.fsl.regexp;

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

public class Regexp {
    public static void main(String[] args) {
        String content="在这个数字化的时代,数据无处不在。例如一份项目报告:“项目 X 的进展报告,截止到 2023 年 10 月,已经完成了 75% 的工作量。其中,A 模块的编码工作(主要由程序员 Tom 负责)已经顺利结束。下一步是进行 B 模块的测试工作,预计需要 15 天。此次项目的成功对于公司开拓市场至关重要,它将帮助我们在 @#$% 行业中占据更有利的地位。我们要确保每一个细节都不出错,包括数据的准确性、代码的规范性等,避免出现像之前项目中的 *&^ 错误。”";
        Pattern pattern6=Pattern.compile("\\d{2}");//{n}代表连续出现n次前面的文本 在这里代表连续出现三次数字
        Pattern pattern7=Pattern.compile("\\。");

        Matcher matcher=pattern6.matcher(content);
        int no=0;
        while(matcher.find()){
            System.out.println("find:"+" "+(++no)+" "+matcher.group(0));
        }
    }
}

 

 字符匹配符

 

 

 

 

 

package com.hspedu.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * 演示字符匹配符 的使用
 */
public class Regexp {
    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));
        }
    }
}

 

 

选择匹配符

 

限定符

 

 

 

 

package com.fsl.regexp;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * 演示限定符的使用
 */
public class RegExp {
    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));
        }
    }
}

 

结果:java默认贪婪匹配 尽可能匹配多的

 

 

package com.hspedu.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * 非贪婪匹配
 */
public class RegExp {
    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));
        }
    }
}

 

定位符

 

 

package com.fsl.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * 演示定位符的使用
 */
public class RegExp {
    public static void main(String[] args) {
        String content = "hanshunping sphan nnhan";
        //String content = "123-abc";
        //以至少1个数字开头,后接任意个小写字母的字符串
        //String regStr = "^[0-9]+[a-z]*";
        /*如果content="a123abc",则匹配不到
          如果content="123abc12",则匹配结果为123abc
       */

        //以至少1个数字开头, 必须以至少一个小写字母结束
        //String regStr = "^[0-9]+\\-[a-z]+$";
        //如果content="123abc12",则匹配不到

        //表示匹配边界的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));
        }
    }
}

 

 分组

 package com.hspedu.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * 分组:
 */
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"));
        }
    }
}

 

 特别分组

 

package com.fsl.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * 演示非捕获分组, 语法比较奇怪
 */
public class RegExp {
    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));
        }
    }
}

个人理解:

  1. 非捕获分组(?:)

    • 功能:主要是将括号内的内容作为一个整体来参与匹配过程。它用于组合一个或多个正则表达式子模式,让这些子模式被视为一个单元进行匹配操作。
    • 匹配结果:括号内的内容会包含在整个匹配结果中。例如,对于正则表达式abc(?:def|ghi),如果匹配成功,会得到一个包含abc以及def或者ghi的完整匹配部分。
    • 用途示例:在复杂的正则表达式中,用于对一些重复出现的模式组合进行整体匹配,同时避免捕获这些组合内容用于后续提取,减少不必要的捕获组开销。
  2. 正向肯定预查(?=)

    • 功能:这是一种零宽度正预测先行断言。用于检查当前位置之后(不包括当前位置)是否能够匹配指定的模式。它只是一个条件判断,不消耗字符用于匹配结果。
    • 匹配结果:只返回满足预查条件之前的部分作为匹配内容。例如,对于正则表达式a(?=b),在字符串"abc"中,仅a是匹配结果,b只是用于判断a之后是否符合条件,不包含在最终匹配内容中。
    • 用途示例:用于在匹配时要求某个字符或模式后面必须紧跟特定的其他字符或模式,但又不想把紧跟的内容包含在匹配结果中,比如在提取 HTML 标签中的属性值时,确保属性名后跟着等号。
  3. 正向否定预查(?!)

    • 功能:这是一种零宽度正预测否定先行断言。用于检查当前位置之后(不包括当前位置)是否不能匹配指定的模式。同样是条件判断,不消耗字符用于匹配结果。
    • 匹配结果:只返回满足否定预查条件之前的部分作为匹配内容。例如,对于正则表达式a(?!b),在字符串"acd"中,a是匹配结果,因为a之后不是b
    • 用途示例:用于排除某些特定模式紧跟在某个字符或模式之后的情况,如在匹配单词时,确保某个单词后面不跟着特定的标点符号。

20.5 正则表达式三个常用类

 

 

 

 

package com.fsl.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * Matcher 类的常用方法
 */
public class MatcherMethod {
    public static void main(String[] args) {
        String content = "hello edu jack hspedutom hello smith hello hspedu hspedu";
        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 有 hspedu 替换成 韩顺平教育
        regStr = "hspedu";
        pattern = Pattern.compile(regStr);
        matcher = pattern.matcher(content);
        //注意:返回的字符串才是替换后的字符串 原来的 content 不变化
        String newContent = matcher.replaceAll("韩顺平教育");
        System.out.println("newContent=" + newContent);
        System.out.println("content=" + content);
    }
}

 

 

20.6 分组 捕获 反向引用

 

 

package com.hspedu.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * 反向引用
 */
public class RegExp12 {
    public static void main(String[] args) {
        String content = "h1234el9876lo33333 j12324-333999111a1551ck14 tom11 jack22 yyy12345 xxx";
        //要匹配两个连续的相同数字 :  (\\d)\\1
        //String regStr = "(\\d)\\1";\\1代表分组1号,也就是(\\d)
        //要匹配五个连续的相同数字: (\\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));
        }
    }
}

 

 

package com.hspedu.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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);
    }
}

 

个人理解:

在正则表达式的运用中,反向引用在匹配和替换两个不同阶段有着不同的使用方式:

匹配阶段

  • 使用\1\2等形式(\后面跟数字)进行反向引用。
  • 这些引用是在正则表达式自身内部构建复杂匹配模式时使用的,比如用于识别对称模式、重复模式等,帮助正则表达式引擎确定输入字符串是否符合特定要求,但此阶段主要是为了定义匹配规则,并非对匹配到的内容进行修改。

替换阶段

  • 当进行替换操作,如使用Matcher类的replaceAll()replaceFirst()方法时,采用$符号开头的反向引用(如$1$2等)。
  • 在替换字符串中,通过$开头的反向引用可以指定要插入或替换的内容与之前捕获组的关系,从而根据匹配时捕获的内容灵活构建替换后的字符串。

总之,反向引用在匹配和替换阶段各有其特定的表示形式和用途,都是为了更有效地利用捕获组的内容来满足不同的正则表达式处理需求。

20.7 String类中使用正则表达式

 替换功能

 

package com.fsl.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegExp {
    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);

    }
}

 判断功能

package com.fsl.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegExp {
    public static void main(String[] args) {
        //要求 验证一个 手机号, 要求必须是以138 139 开头的
        String content = "13888889999";
        if (content.matches("1(38|39)\\d{8}")) {
            System.out.println("验证成功");
        } else {
            System.out.println("验证失败");
        }


    }
}

 

 分割功能

package com.fsl.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegExp {
    public static void main(String[] args) {
        //要求按照 # 或者 - 或者 ~ 或者 数字 来分割
        String content = "hello#abc-jack12smith~北京";
        String[] split = content.split("#|-|~|\\d+");
        for (String s : split) {
            System.out.println(s);
        }
    }
}

 

 


原文地址:https://blog.csdn.net/weixin_60566743/article/details/144212757

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!