正则表达式

正则表达式

1. 快速入门

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

1.1.1 极速体验正则表达式威力
  1. 提取文章中所有的英文单词

    package com.song.regexp;
    
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    /**
     * 体验正则表达式的威力,给我们文本处理带来了哪些便利
     */
    public class Regexp_ {
        public static void main(String[] args) {
    
            //假定我们编写了爬虫,从百度页面得到了如下文本
            String content = "Java平台由Java虚拟机(Java Virtual Machine)和Java " +
                    "应用编程接口(Application Programming Interface、简称API)构成。" +
                    "Java 应用编程接口为Java应用提供了一个独立于操作系统的标准接口,可分为基本部分和扩展部分。" +
                    "在硬件或操作系统平台上安装一个Java平台之后,Java应用程序就可运行。" +
                    "Java平台已经嵌入了几乎所有的操作系统。这样Java程序可以只编译一次,就可以在各种系统中运行。" +
                    "Java应用编程接口已经从1.1x版发展到1.2版。常用的Java平台基于Java1.8,最近版本为Java19。";
    
            //现要求提取文章中所有的英文单词
            //(1) 传统方式:使用遍历方式,代码量大且效率不高
            //(2) 正则表达式技术
    
            //1.先创建一个Pattern对象(一个模式对象)
            //  可以理解为正则表达式对象
            Pattern pattern = Pattern.compile("[a-zA-Z]+");
            //2.创建一个匹配器对象
            //理解: 就是 matcher 匹配器按照 pattern(模式/模样),到 content 文本中去匹配
            Matcher matcher = pattern.matcher(content);
            //3.可以开始循环匹配
            while (matcher.find()){
                //匹配内容,文本,放到 m.group(0)
                System.out.println("找到:"+matcher.group(0));
            }
        }
    }
    
  2. 提取文章中所有的数字

    package com.song.regexp;
    
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    /**
     * 体验正则表达式的威力,给我们文本处理带来了哪些便利
     */
    public class Regexp_ {
        public static void main(String[] args) {
    
            //假定我们编写了爬虫,从百度页面得到了如下文本
            String content = "Java平台由Java虚拟机(Java Virtual Machine)和Java " +
                    "应用编程接口(Application Programming Interface、简称API)构成。" +
                    "Java 应用编程接口为Java应用提供了一个独立于操作系统的标准接口,可分为基本部分和扩展部分。" +
                    "在硬件或操作系统平台上安装一个Java平台之后,Java应用程序就可运行。" +
                    "Java平台已经嵌入了几乎所有的操作系统。这样Java程序可以只编译一次,就可以在各种系统中运行。" +
                    "Java应用编程接口已经从1.1x版发展到1.2版。常用的Java平台基于Java1.8,最近版本为Java19。";
    
            //现要求提取文章中所有的英文单词
            //提取文章中所有的数字
            //(1) 传统方式:使用遍历方式,代码量大且效率不高
            //(2) 正则表达式技术
    
            //1.先创建一个Pattern对象(一个模式对象)
            //  可以理解为正则表达式对象
            //Pattern pattern = Pattern.compile("[a-zA-Z]+");
            Pattern pattern = Pattern.compile("[0-9]+");
            //2.创建一个匹配器对象
            //理解: 就是 matcher 匹配器按照 pattern(模式/模样),到 content 文本中去匹配
            Matcher matcher = pattern.matcher(content);
            //3.可以开始循环匹配
            while (matcher.find()){
                //匹配内容,文本,放到 m.group(0)
                System.out.println("找到:"+matcher.group(0));
            }
        }
    }
    
  3. 提取文章中所有的英文单词和数字

    package com.song.regexp;
    
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    /**
     * 体验正则表达式的威力,给我们文本处理带来了哪些便利
     */
    public class Regexp_ {
        public static void main(String[] args) {
    
            //假定我们编写了爬虫,从百度页面得到了如下文本
            String content = "Java平台由Java虚拟机(Java Virtual Machine)和Java " +
                    "应用编程接口(Application Programming Interface、简称API)构成。" +
                    "Java 应用编程接口为Java应用提供了一个独立于操作系统的标准接口,可分为基本部分和扩展部分。" +
                    "在硬件或操作系统平台上安装一个Java平台之后,Java应用程序就可运行。" +
                    "Java平台已经嵌入了几乎所有的操作系统。这样Java程序可以只编译一次,就可以在各种系统中运行。" +
                    "Java应用编程接口已经从1.1x版发展到1.2版。常用的Java平台基于Java1.8,最近版本为Java19。";
    
            //现要求提取文章中所有的英文单词
            //提取文章中所有的数字
            //提取文章中所有的英文单词和数字
            //(1) 传统方式:使用遍历方式,代码量大且效率不高
            //(2) 正则表达式技术
    
            //1.先创建一个Pattern对象(一个模式对象)
            //  可以理解为正则表达式对象
            //Pattern pattern = Pattern.compile("[a-zA-Z]+");
            //Pattern pattern = Pattern.compile("[0-9]+");
            Pattern pattern = Pattern.compile("([a-zA-Z]+)|([0-9]+)");
            //2.创建一个匹配器对象
            //理解: 就是 matcher 匹配器按照 pattern(模式/模样),到 content 文本中去匹配
            Matcher matcher = pattern.matcher(content);
            //3.可以开始循环匹配
            while (matcher.find()){
                //匹配内容,文本,放到 m.group(0)
                System.out.println("找到:"+matcher.group(0));
            }
        }
    }
    
  4. 提取百度热榜 标题

package com.song.regexp;

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

/**
 * 体验正则表达式的威力,给我们文本处理带来了哪些便利
 */
public class Regexp_ {
    public static void main(String[] args) {

        //假定我们编写了爬虫,从百度页面得到了如下文本
        /*
        String content = "Java平台由Java虚拟机(Java Virtual Machine)和Java " +
                "应用编程接口(Application Programming Interface、简称API)构成。" +
                "Java 应用编程接口为Java应用提供了一个独立于操作系统的标准接口,可分为基本部分和扩展部分。" +
                "在硬件或操作系统平台上安装一个Java平台之后,Java应用程序就可运行。" +
                "Java平台已经嵌入了几乎所有的操作系统。这样Java程序可以只编译一次,就可以在各种系统中运行。" +
                "Java应用编程接口已经从1.1x版发展到1.2版。常用的Java平台基于Java1.8,最近版本为Java19。";
         */
        String content = "<div><div id=\"sanRoot\" theme=\"homepage\" class=\"wrapper c-font-normal rel\"><!--s-data:" +
                "{\"data\":{\"cards\":[{\"component\":\"hotList\",\"content\":[{\"appUrl\":" +
                "\"https://www.baidu.com/s?wd=%E4%BD%A0%E4%BB%AC%E7%9A%84%E5%90%8D%E5%AD%97+%E9%97%AA%E8%80%80%E7%9A%84%E8%B7%AF%E6%A0%87&sa" +
                "=fyb_hp_news&rsv_dl=fyb_hp_news\",\"desc\":\"从“大钊路”到“延乔路”,从“钱学森星”到“屠呦呦星”,他们的名字刻在大街小巷,闪耀在璀璨星空。" +
                "英雄之名,见证艰辛历程,未来之路,更需接续奋斗。\",\"hotChange\":\"same\",\"hotScore\":\"4981676\",\"hotTag\":\"0\",\"img\":" +
                "\"https://fyb-2.cdn.bcebos.com/hotboard_image/2853b6820fd0e88ec87203131e94853b\",\"index\":0,\"indexUrl\":\"\",\"query\":" +
                "\"你们的名字 闪耀的路标\",\"rawUrl\":\"https://www.baidu.com/s?wd=%E4%BD%A0%E4%BB%AC%E7%9A%84%E5%90%8D%E5%AD%97+%E9%97%AA%E8%80%80%E7%9A%84%E8%B7%AF%E6%A0%87" +
                "\",\"show\":[],\"url\":\"https://www.baidu.com/s?wd=%E4%BD%A0%E4%BB%AC%E7%9A%84%E5%90%8D%E5%AD%97+%E9%97%AA%E8%80%80%E7%9A%84%E8%B7%AF%E6%A0%87&sa=fyb_hp_news&rsv_dl=fyb_hp_news" +
                "\",\"word\":\"你们的名字 闪耀的路标\",\"isTop\":true},{\"appUrl\":" +
                "\"https://www.baidu.com/s?wd=%E5%8C%97%E4%BA%AC%E5%B9%BF%E5%91%8A%E5%8D%8F%E4%BC%9A%3A%E5%AF%B9%E8%94%A1%E6%9F%90%E6%9F%90%E5%81%9A%E5%A5%BD%E9%A3%8E%E9%99%A9%E6%8A%8A%E6%8E%A7&sa=fyb_hp_news&rsv_dl=fyb_hp_news" +
                "\",\"desc\":\"7月1日晚,北京广告协会明星代言规范委发布关于对中国内地男歌手蔡某某舆情发酵的风险提示,表示要对蔡某某做好风险把控。" +
                "\",\"hotChange\":\"same\",\"hotScore\":\"4974145\",\"hotTag\":\"3\",\"hotTagImg\":" +
                "\"https://search-operate.cdn.bcebos.com/54a1ed72d00cd07334860b0509489d8b.png\",\"img\":" +
                "\"https://fyb-2.cdn.bcebos.com/hotboard_image/ae2a046b72c3dc81f955c0b819c8b313\",\"index\":0,\"indexUrl\":\"\",\"query\":" +
                "\"北京广告协会:对蔡某某做好风险把控\",\"rawUrl\":";
        //现要求提取文章中所有的英文单词
        //提取文章中所有的数字
        //提取文章中所有的英文单词和数字
        //(1) 传统方式:使用遍历方式,代码量大且效率不高
        //(2) 正则表达式技术

        //1.先创建一个Pattern对象(一个模式对象)
        //  可以理解为正则表达式对象
        //Pattern pattern = Pattern.compile("[a-zA-Z]+");
        //Pattern pattern = Pattern.compile("[0-9]+");
        //Pattern pattern = Pattern.compile("([a-zA-Z]+)|([0-9]+)");
        Pattern pattern = Pattern.compile("\"desc\":\"(\\S*)\"");
        //2.创建一个匹配器对象
        //理解: 就是 matcher 匹配器按照 pattern(模式/模样),到 content 文本中去匹配
        Matcher matcher = pattern.matcher(content);
        //3.可以开始循环匹配
        while (matcher.find()){
            //匹配内容,文本,放到 m.group(0)
            //System.out.println("找到:"+matcher.group(0));
            System.out.println("找到:"+matcher.group(1));
        }
    }

结论:正则表达式是处理文本的利器

//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*)\"");

1.2 再提出几个问题?

  1. 给你一个字符串(或文章),请你找出所有四个数字连在一起的子串?
  2. 给你一个字符串(或文章),请你找出所有四个数字连在一起的子串,
  3. 并且这四个数字要满足:第一位与第四位相同,第二位与第三位相同 ,
    • 比如1221, 5775

  1. 请验证输入的邮件,是否符合电子邮件格式
  2. 请验证输入的手机号,是否符合手机号格式

1.3 解决之道-正则表达式

  1. 上述问题如果只用我们前面学到的内容来处理还是比较困难的;
  2. 为了解决上述问题,Java提供了正则表达式技术,专门用于处理类似文本问题
  3. 简单的说:正则表达式是对字符串执行模式匹配的技术
  4. 正则表达式: regular expression => 我们通常会将其简写成RegExp

1.4 正则表达式基本介绍

  1. 一个正则表达式,就是用某种模式去匹配字符串的一个公式。很多人因为它们看上去比较古怪而且复杂所以不敢去使用,不过,经过练习后,就觉得这些复杂的表达式写起来还是相当简单的,而且,一旦你弄懂它们,你就能把数小时辛苦而且易错的文本处理工作缩短在几分钟 (甚至几秒钟)内完成
  2. 特别强调:正则表达式不是只有iava才有,实际上很多编程语言都支持正则表达式进行字符串操作!如图所示

1.5 正则表达式底层实现(很重要)

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

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

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

代码实现及源码分析:

package com.song.regexp;

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

/**
 * 分析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表示任意一个0-9的数字
        // 所以下面代表四个连在一起的数字
        //String regStr = "\\d\\d\\d\\d";
        String regStr = "(\\d\\d)(\\d\\d)";
        //2.创建模式对象
        Pattern pattern = Pattern.compile(regStr);
        //3.创建匹配器
        //  创建匹配器matcher,按照正则表达式的规则 去匹配 content字符串
        Matcher matcher = pattern.matcher(content);

        //4.开始匹配
        /**
         第一轮
         * matcher.find() 完成的任务
         * 1.根据指定的规则,定位满足规则的子字符串(比如1998)
         * 2.找到后将 子字符串开始的索引记录到 matcher 对象的属性 int[] groups;
         *      group[0] = 0 , 把该字符串的结束的索引+1的值记录到 group[1] = 4
         * 3.同时记录 oldLast 的值为 子字符串的结束的 索引+1的值即4,
         *      即下次执行find时,就从4开始匹配
         *
         * 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.根据 group(0) 和 group(1) 的记录的位置,从 content 开始截取子字符串返回
         *      就是[0,4) 前闭后开 即包含 0 但是不包含 索引为 4 的位置
         *
         第二轮
         * matcher.find() 完成的任务
         * 1.根据指定的规则,定位满足规则的子字符串(比如第二个数字1999)
         * 2.找到后将 子字符串开始的索引记录到 matcher 对象的属性 int[] groups;
         *      group[0] = 31 , 把该字符串的结束的索引+1的值记录到 group[1] = 35
         * 3.同时记录 oldLast 的值为 子字符串的结束的 索引+1的值即4,
         *      即下次执行find时,就从4开始匹配
         *
         * 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.根据 group(0) 和 group(1) 的记录的位置,从 content 开始截取子字符串返回
         *      就是[31,35) 前闭后开 即包含 31 但是不包含 索引为 35 的位置
         *
         * 后面查找的方法还是按照这样进行
         *
         上面的源码分析是没有考虑分组的,现在考虑分组的情况
         * matcher.find() 完成的任务(考虑分组)
         * 什么是分组,比如 (\d\d)(\d\d) ,正则表达式中有()表示分组,
         *      第 1 个()表示第一组 , 第 2 个()表示第二组
         *
         * 1.根据指定的规则,定位满足规则的子字符串(比如1998)
         * 2.找到后将 子字符串开始的索引记录到 matcher 对象的属性 int[] groups;
         *     2.1 group[0] = 0 , 把该字符串的结束的索引+1的值记录到 group[1] = 4
         *
         * 分组就变成 (19)(98)
         *     2.2 记录第1组匹配到的字符串 group[2] = 0 , group[3] = 2
         *     2.3 记录第1组匹配到的字符串 group[4] = 2 , group[5] = 4
         *     2.4 如果还有更多的分组以此类推...
         * 3.同时记录 oldLast 的值为 子字符串的结束的 索引+1的值即4,
         *      即下次执行find时,就从4开始匹配
         *
         * 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.根据 group(0) 和 group(1) 的记录的位置,从 content 开始截取子字符串返回
         *      就是[0,4) 前闭后开 即包含 0 但是不包含 索引为 4 的位置
         *
         *
         */
        while (matcher.find()){
            //小结:
            //1.如果正则表达式有() 即分组
            //2.取出匹配的字符串规则如下
            //3.group(0) 表示匹配到的子字符串
            //4.group(1) 表示匹配到的子字符串的第一组字串
            //5.group(2) 表示匹配到的子字符串的第二组字串
            //6.但是分组的数不能超过本身有的分组,即不能越界
            System.out.println("找到:"+matcher.group(0));
            //底层源码是return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
            //所以下面分组的 group(1) 表示返回 group(2) , group(3)
            System.out.println("第一组()匹配到的值="+matcher.group(1));
            //下面分组的 group(2) 表示返回 group(4) , group(5)
            System.out.println("第二组()匹配到的值="+matcher.group(2));
        }
    }
}

分组情况下的debug情况

2. 正则表达式基本语法

2.1 基本介绍

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

  1. 限定符
  2. 选择匹配符
  3. 分组组合和反向引用符
  4. 特殊字符
  5. 字符匹配符
  6. 定位符

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

\\符号 说明: 在我们使用正则表达式去检索某些特殊字符的时候,需要用到转义符号,否
则检索不到结果,甚至会报错的。
案例: 用$ 去匹配“abc$(”用(去匹配 “abc$(”会怎样 ?

再次提示:Java 的正则表达式中,两个\\代表其他语言中的一个\
                             
常见的转义符有如下几种:
  . * + ( ) $ / \ ? [ ] ^ { )

简单代码演示:

package com.song.regexp;

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

/**
 * 演示转义字符的使用
 */
public class RegExp02 {
    public static void main(String[] args) {
        String content = "abc$(a.b.c(123(";
        //匹配 ( 需要这样写 \\(
        //匹配 . 需要这样写 \\.
        //其他的同理
        //String regStr = "\\(";
        String regStr = "\\.";
        //这里如果没有转义符\\就会报错
        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()){
            System.out.println("找到:"+matcher.group(0));
        }
    }
}

2.3 元字符-字符匹配符

2.3.1 应用实例
1. [a-z] 说明:

   [a-z] 表示可以匹配a-z中任意一个字符;

   同理[A-Z] 可以匹配A-Z中任意一个字符;

   [0-9] 表示可以匹配0-9中任意一个字符;

2. java正则表达式默认是区分字母大小写的,如何实现不区分大小写

   - (?i)abc 表示abc都不区分大小写
   - a(?i)bc 表示bc不区分大小写
   - a((?i)b)c 表示只有b不区分大小写
   - Pattern pat = Pattern.compile(regEx, Pattern.CASE INSENSITIVE);

3. [^a-z] 说明: 
   - [^a-z]  表示可以匹配不是a-z中的任意一个字符;
   - [a-z]{2} 又会得到什么结果呢? 答:代表连续两个不是a-z中的任意字符;
   - [^A-Z] 表示可以匹配不是A-Z中的任意一个字符
   - [^0-9] 表示可以匹配不是0-9中的任意一个字符
       
4. [abcd] 表示可以匹配abcd中的任意一个字符
   
5. [^abcd] 表示可以匹配不是abcd中的任意一个字符
       当然上面的abcd 你可以根据实际情况修改,以适应你的需求
       
6. \\d 表示可以匹配0-9的任意一个数字,相当于 [0-9]7. \\D 表示可以匹配不是0-9中的任意一个数字,相当于[^0-9]
8. \\w 匹配任意英文字符、数字和下划线,相当于[a-zA-Z0-9]
9. \\W 相当于 [^a-zA-Z0-9 ]和\\w 刚好相反
10. \\s 匹配何空白字符(空格,制表符等)
11. \\S 匹配任何非空白字符和 \\s刚好相反
12. .匹配除 \n 之外的所有字符,如果要匹配.本身则需要使用 \\.

下面进行简单的代码演示:

package com.song.regexp;

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

/**
 * 演示字符匹配符的使用
 */
public class RegExp03 {
    public static void main(String[] args) {
        String content = "a11c88abc.Abc";
        //String regStr = "[a-z]";//匹配a-z中任意一个字符
        //String regStr = "[A-Z]";//匹配A-Z中任意一个字符

        //区分大小写
        //String regStr = "abc";//匹配 abc 字符串 [默认区分大小写]
        //区分大小写方法一:添加 (?i)
        //String regStr = "(?i)abc";//匹配 abc 字符串 [不区分大小写]
        //String regStr = "a(?i)bc";//匹配 abc 字符串 [bc不区分大小写]
        //String regStr = "a((?i)b)c";//匹配 abc 字符串 [b不区分大小写]

        //String regStr = "[0-9]";//匹配 0-9之间的任意一个数字

        //String regStr = "[^a-z]";//匹配不是a-z中的任意一个字符

        //String regStr = "[^a-z]{2}";//匹配连续两个不是a-z中的任意字符

        //String regStr = "[^A-Z]";//匹配不是A-Z中的任意一个字符

        //String regStr = "[^0-9]";//匹配不是0-9中的任意一个字符

        //以下这些就不举例说明了
        //4. [abcd] 表示可以匹配abcd中的任意一个字符

        //5. [^abcd] 表示可以匹配不是abcd中的任意一个字符
        //       当然上面的abcd 你可以根据实际情况修改,以适应你的需求

        //6. \\d 表示可以匹配0-9的任意一个数字,相当于 [0-9]。
        //7. \\D 表示可以匹配不是0-9中的任意一个数字,相当于[^0-9]
        //8. \\w 匹配任意英文字符、数字和下划线,相当于[a-zA-Z0-9]
        //9. \\W 相当于 [^a-zA-Z0-9 ]和\\w 刚好相反
        //10. \\s 匹配何空白字符(空格,制表符等)
        //11. \\S 匹配任何非空白字符和 \\s刚好相反
        //12. .匹配除 \n 之外的所有字符,如果要匹配.本身则需要使用 \\.

        //String regStr = ".";//匹配除 \n 之外的所有字符,
        String regStr = "\\.";//如果要匹配.本身则需要使用 \\.

        //Pattern pattern = Pattern.compile(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));
        }
    }
}

2.4 元字符-选择匹配符

在匹配某个字符串的时候是选择性的,即: 既可以匹配这个,又可以匹配那个;

这时你需要用到 选择匹配符号 |

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lxcm8n5Q-1688550063975)(E:\Java study\Markdown\本地图片\选择匹配符.png)]

简单代码演示:

package com.song.regexp;

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

/**
 * 演示选择匹配符的使用
 */
public class RegExp04 {
    public static void main(String[] args) {
        String content = "sys 学 java@study";
        String regStr = "sys|学|study";

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

2.5 元字符-限定符

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

2.5.1 应用案例
1.  (n}说明:
   
     n表示出现的次数,比如 a{3},1{4},\\d{2}

2.  (n,m}说明:
   
     n表示至少出现的n次最多m次,比如 a{3,4},1{4,5},\\d{2,5}

3.  +说明

    +表示出现1次到任意多次 ,比如 a+ ,1+, \\d+;

4.  *说明
    *表示出现0次到任意多次 ,比如 a*,1*,\\d*;

5.  ? 说明:

    ? 表示出现0次到1次,比如 a?1?, \\d? ;

简单代码演示:

package com.song.regexp;

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

/**
 * 演示限定符的使用
 */
public class RegExp05 {
    public static void main(String[] args) {
        String content ="a1aaa111bcd1111cd";
        //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位数

        //a+ ,1+, \\d+
        //String regStr = "a+"; //表示匹配 一个a或者多个a
        //String regStr = "1+"; //表示匹配 一个1或者多个1
        //String regStr = "\\d+"; //匹配 2 位数或者 3,4,5位数

        //a*,1*,\\d*
        //String regStr = "a*"; //匹配 0 个 a 或者多个 a

        //a?,1?, \\d?
        String regStr = "a1?"; //匹配 a 或者 a1

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

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

2.6 元字符-定位符

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

简单代码演示:

package com.song.regexp;

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

/**
 * 演示定位符的使用
 */
public class RegExp06 {
    public static void main(String[] args) {
        //String content ="1-aba";
        String content ="112sys120asys 221sys";
        //以至少 1 个数字开头,后接任意个小写字母的字符串
        //String regStr = "^[0-9]+[a-z]*";
        //以至少 1 个数字开头, 必须以至少一个小写字母结束
        //String regStr = "^[0-9]+[a-z]+$";
        //以至少 1 个数字开头, 必须以至少一个小写字母结束,并且中间要有-
        //String regStr = "^[0-9]+\\-[a-z]+$";

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

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

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

2.7 分组

  1. 常用分组分为 非命名捕获 和 命名捕获,如下图

简单代码演示:

package com.song.regexp;

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

/**
 * 分组
 */
public class RegExp07 {
    public static void main(String[] args) {
        String content ="1122sys 1200asys ns221sys";

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

        //1.非命名捕获
        //String regStr = "(\\d\\d)(\\d\\d)";//匹配四个数组字符串

        //2.命名捕获
        String regStr = "(?<s1>\\d\\d)(?<s2>\\d\\d)";//匹配四个数组字符串

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

        while (matcher.find()){
            System.out.println("找到:"+matcher.group(0));
            //1.非命名捕获
            //System.out.println("第1个分组内容="+matcher.group(1));
            //System.out.println("第2个分组内容="+matcher.group(2));

            //2.命名捕获
            System.out.println("第1个分组内容[通过组名]="+matcher.group("s1"));
            System.out.println("第2个分组内容[通过组名]="+matcher.group("s2"));
        }
    }
}
  1. 下图为三个特别分组:

简单代码演示:

package com.song.regexp;

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

/**
 * *演示非捕获分组, 语法比较奇怪
 */
public class RegExp08 {
    public static void main(String[] args) {
        String content = "hello sys学java jack sys看java sys练java hello sys用java";
        
        //	找到 sys学java 、sys看java、sys练java 子字符串
        //String regStr = "sys学java|sys看java|sys练java";

        //上面的写法可以等价非捕获分组, 注意:不能 matcher.group(1)
        //String regStr = "sys(?:学java|看java|练java)";

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

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

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

2.8 非贪婪匹配元字符

简单代码演示:

package com.song.regexp;

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

/**
 * 非贪婪匹配
 */
public class RegExp09 {
    public static void main(String[] args) {
        String content = "abcd1111111 ok";
        //正常是贪婪匹配
        //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));
        }
    }
}

2.9 应用实例

对字符串进行如下验证:

  1. 汉字

  2. 邮政编码

    要求: 是1-9开头的一个六位数。比如: 123890

  3. QQ号码

    要求: 是1-9开头的一个(5位数-10位数) 比如: 12389,1345687,187698765

  4. 手机号码

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

  5. URL: 如图:https://www.bilibili.com/video/BV1fh411y7R8?from=search&seid=1831060912083761326

前面1-4的验证代码:
package com.song.regexp;

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

/**
 * 正则表达式的应用实例
 */
public class RegExp10 {
    public static void main(String[] args) {
        String content = "13588889999";
        //1. 汉字
        //String regStr = "^[\u0391-\uffe5]$";
        //2. 邮政编码
        //   要求: 是1-9开头的一个六位数。比如: 123890
        //String regStr = "^[1-9]\\d{5}$";
        //3. QQ号码
        //   要求: 是1-9开头的一个(5位数-10位数)  比如: 12389,1345687,187698765
        //String regStr = "^[1-9]\\d{4,9}$";
        //4. 手机号码
        //   要求: 必须以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("不满足格式");
        }
    }
}
URL的验证:
package com.song.regexp;

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

/**
 * 演示正则表达式的使用
 */
public class RegExp11 {
    public static void main(String[] args) {
        String content = "https://www.bilibili.com/video/BV1fh411y7R8/?from=search" +
                "&seid=1831060912083761326&vd_source=42091d6af57d142187f914579471a0c7";
        //思路分析:
        //1. ((http|https)://) 匹配的是开始部分的 https://或者 http://
        //   但是有些网址又不带 http 开头,所以开头可以写 ((http|https)://)?
        //2. ([\w-]+\.)+[\w-]+ 匹配的是中间部分的 www.bilibili.com
        //3. (\/[\w-?=&/%.]*)? 匹配的是最后那部分,因为那部分可能有可能没有,所以最后加了一个?
        //  /?from=search&seid=1831060912083761326&vd_source=42091d6af57d142187f914579471a0c7

        //注意:[. ? *] 表示匹配的他们本身,在[]里面的情况下
        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("不满足格式");
        }
    }
}
对于URL中提到的注意点的举例说明
package com.song.regexp;

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

public class TestTemp {
    public static void main(String[] args) {
        String content = "dsffds 41s d.sa";

        //注意:[. ? *] 表示匹配的他们本身,在[]里面的情况下
        //在这种情况下就是匹配 除了 \n 的所有字符
        //String regStr = ".";

        //但是这种情况下就是匹配的 . 本身
        String regStr = "[.]";

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

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

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

Pattern 类:

  • pattern 对象是一个正则表达式对象。
  • Pattern 类没有公共构造方法。
  • 要创建一个 Pattern 对象,调用其公共静态方法,它返回一个 Pattern 对象。
  • 该方法接受一个正则表达式作为它的第个参数, 比: Pattern r = Pattern.compile(pattern);

Matcher 类:

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

PatternSyntaxException:

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

3.1 Pattern类的方法matches

  1. 简单代码演示:
package com.song.regexp;

import java.util.regex.Pattern;

/**
 * 演示 matches 方法,用于整体匹配, 在验证输入的字符串是否满足条件使用
 */
public class PatternMethod {
    public static void main(String[] args) {
        String content = "hello abc hello,sys学java";
        //String reStr = "hello"; // false
        String reStr = "hello.*"; // true

        boolean matches = Pattern.matches(reStr, content);
        /*match源码
        public static boolean matches(String regex, CharSequence input) {
            Pattern p = Pattern.compile(regex);
            Matcher m = p.matcher(input);
            return m.matches();
        }
         */
        System.out.println("整体匹配 = "+matches);
    }
}
  1. match方法一览

简单的方法使用代码演示

package com.song.regexp;

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

/**
 * Matcher 类的常用方法
 */
public class MatcherMethod {
    public static void main(String[] args) {
        String content = "hello smith sys jack hello lucy hello";
        String regStr = "hello";
        //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());
            //==============
            //0 第一个hello的第一个字母的位置group(0)
            //5 第一个hello的最后一个字母的位置group(5)
            //==============
            //21 第二个hello的第一个字母的位置group(21)
            //26 第二个hello的最后一个字母的位置group(26)
            //==============
            //32 第三个hello的第一个字母的位置group(32)
            //37 第三个hello的最后一个字母的位置group(37)

            //也可以直接用 content.substring() 直接找到hello
            System.out.println("找到: " + content.substring(matcher.start(), matcher.end()));
            //==============
            //找到: hello
            //==============
            //找到: hello
            //==============
            //找到: hello
        }

        //整体匹配方法,常用于去校验某个字符串是否满足某个规则
        System.out.println("整体匹配= " + matcher.matches());
        //当 String regStr = "hello"; 的时候,输出 整体匹配= false
        //当 String regStr = "hello.*"; 的时候,输出 整体匹配= true

        //完成如果content 有 jack 替换成
        //replace
        regStr = "jack";
        pattern = Pattern.compile(regStr);
        matcher = pattern.matcher(content);
        //注意:返回的字符串才是替换后的字符串 原来的 content 不变化
        String newContent = matcher.replaceAll("学");
        System.out.println("newContent = " + newContent);
        //newContent = hello smith sys 学 hello lucy hello
        System.out.println("content = " + content);
        //content = hello smith sys jack hello lucy hello
    }
}

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

4.1 前提引出

请看下面问题:

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

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

4.2 介绍

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

  1. 分组:

    我们可以用圆括号组成一个比较复杂的匹配模式,那么一个圆括号的部分我们可以看作是一个子表达式/一个分组。

  2. 捕获:

    把正则表达式中子表达式/分组匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用,从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。

    组0代表的是整个正则式

  3. 反向引用:

    圆括号的内容被捕获后,可以在这个括号后被使用,从而写出一个比较实用的匹配模式,这个我们称为反向引用,这种引用既可以是在正则表达式内部,也可以是在正则表达式外部,内部反向引用\\分组号,外部反向引用 $分组号

4.3 情景案例

案例一
  1. 要匹配两个连续的相同数字:

    (\\d)\\1
    
  2. 要匹配五个连续的相同数字:

    (\\d)\\1{4}
    
  3. 要匹配个位与千位相同,十位与百位相同的数 5225,1551

    (\\d)(\\d)\\2\\1
    
  4. 请在字符串中检索商品编号,形式如:12321-333999111 这样的号码,要求满足前面是一个五位数,然后一个-号,然后是-个九位数,连续的每三位要相同

    \\d{5}-(\\d)\1{2}(\\d)\2{2}(\\d)\3{2}
    
  5. 简单代码演示:

package com.song.regexp;

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

/**
 * 反向引用
 */
public class RegExp12 {
    public static void main(String[] args) {
        String content = "hello jack1221 lucy11111 sys12321-333999111 yyy";
        //找到两个连续的相同的数字
        //String regStr = "(\\d)\\1";
        //找到五个连续的相同的数字
        //String regStr = "(\\d)\\1{4}";
        //找到个位与千位相同,十位与百位相同的数 5225,1551
        //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));
        }
    }
}
案例二:经典的结巴程序

把 类似 : “我…我要…学学学学…编程 java!”;

通过正则表达式 修改成 “我要学编程 java”

简单代码演示:

package com.song.regexp;

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

/**
 * 结巴程序
 */
public class RegExp13 {
    public static void main(String[] args) {
        /**
         * 把 类似	: "我....我要....学学学学....编程 java!";
         * 通过正则表达式 修改成	"我要学编程 java"
         */

        String content = "我....我要....学学学学....编程 java!";
        //思路:
        //1.去掉所有的.
        String regStr = "\\.";
        Pattern pattern = Pattern.compile(regStr);
        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);
        //content = 我要学编程 java!
    }
}

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

5.1 替换功能

Stringpublic String replaceAll(String regex,String replacement)

将上面这段文字中的 JDK1.3 和 JDK1.4 统一替换成 JDK

5.2 判断功能

Stringpublic boolean matches(String regex){} //使用 Pattern 和 Matcher 类

要求:

验证一个手机号,要求必须以 138、139开头

5.3 分割功能

Stringpublic String[] split(String regex)

要求:

按照 # 或者 - 或者 ~ 或者数字来分割

5.4 代码实现

使用简单的代码演示上述三个在String 类中使用正则表达式的功能:

package com.song.regexp;

import java.util.regex.Pattern;

public class StringReg {
    public static void main(String[] args) {
        //1.替换功能
        String content = "2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布," +
                "几周后其获得了Apple公司MacOS X的工业标准的支持。" +
                "2001年9月24日,J2EE1.3发布。2002年2月26日,J2SE1.4发布。" +
                "自此Java的计算能力有了大幅提升,与J2SE1.3相比,其多了近62%的类和接口。";
        //将上面这段文字中的 JDK1.3 和 JDK1.4 统一替换成 JDK
        content = content.replaceAll("JDK1\\.3|JDK1\\.4","JDK");
        System.out.println(content);

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

        //3.分割功能
        //要求:
        //按照 # 或者 - 或者 ~ 或者数字来分割
        content = "hello#jack-lucy66sys~study~java";
        String[] split = content.split("#|-|~|\\d+");
        for (String s:split){
            System.out.println(s);
        }
    }
}

6. 应用实例

案例一

验证电子邮件格式是否合法 Homework01.java

规定电子邮件规则为:

  1. 只能有一个@
  2. @前面是用户名,可以是a-z A-Z 0-9 -字符
  3. @后面是域名,并且域名只能是英文字母,
  4. 比如 sohu.com 或者 tsinghua.org.cn
  5. 写出对应的正则表达式,验证输入的字符串是否为满足规则
  6. 简单代码演示:
package com.song.regexp;

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

public class Homework01 {
    public static void main(String[] args) {
        /**
         * 验证电子邮件格式是否合法 Homework01.java
         * 规定电子邮件规则为:
         * 1. 只能有一个@
         * 2. @前面是用户名,可以是a-z A-Z 0-9 -字符
         * 3. @后面是域名,并且域名只能是英文字母,
         * 4. 比如 sohu.com 或者 tsinghua.org.cn
         * 5. 写出对应的正则表达式,验证输入的字符串是否为满足规则
         */
        String content = "1241955497@qq.com";
        String regStr = "[\\w]+@([a-zA-Z]+\\.)+[a-zA-Z]+";

        //说明:
        //1. String的 matches 是整体匹配,
        // 所以我们在写 regStr的时候可以不加 "^ $"
        //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();
         *     }
         *
         * Matcher 的 matches
         * 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("匹配失败");
        }
    }
}

案例二

要求验证是不是整数或者小数 Homework02.java

提示:这个题要考虑正数和负数

比如: 123 -345 34.89 -87.9 -0.01 0.45 等

简单代码演示:

package com.song.regexp;

public class Homework02 {
    public static void main(String[] args) {
        /**
         * 要求验证是不是整数或者小数 Homework02.java
         * 提示:这个题要考虑正数和负数
         * 比如: 123 -345 34.89 -87.9 -0.01 0.45 等
         */
        String content = "-87.9";
        //思路分析:
        //(1)  [-]?代表整数或者负数
        //(2)  ([1-9]\d*|0)代表开头是1-9后面有任意数字或者只有一个0
        //          为了避免出现 0012 类似的情况
        // (3)  (\.\d+)?代表是小数或者整数
        boolean matches = content.matches("^[-]?([1-9]\\d*|0)(\\.\\d+)?$");
        System.out.println(matches);
    }
}

案例三

对一个url进行解析 Homework03.java

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

  1. 要求得到协议是什么? http
  2. 域名是什么? www.sohu.com
  3. 端口是什么? 8080
  4. 文件名是什么? index.htm
  5. 简单代码演示如下:
package com.song.regexp;

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

public class Homework03 {
    public static void main(String[] args) {
        /**
         *对一个url进行解析 Homework03.java
         * http://www.sohu.com:8080/abc/index.htm
         * 1. 要求得到协议是什么?			http
         * 2. 域名是什么?				www.sohu.com
         * 3. 端口是什么?				8080
         * 4. 文件名是什么?				index.htm
         */
        String content = "http://www.sohu.com:8080/abc/index.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));
        }
    }
}

7. 常用的正则表达式大全(可根据自己的业务改写)

一、校验数字的表达式

1 数字:^[0-9]*$
2 n位的数字:^\d{n}$
3 至少n位的数字:^\d{n,}$
4 m-n位的数字:^\d{m,n}$
5 零和非零开头的数字:^(0|[1-9][0-9]*)$
6 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
71-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$
8 正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
9 有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
101~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
11 非零的正整数:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$
12 非零的负整数:^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$
13 非负整数:^\d+$ 或 ^[1-9]\d*|0$
14 非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
15 非负浮点数:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
16 非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
17 正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
18 负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
19 浮点数:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$

    
二、校验字符的表达式

1 汉字:^[\u4e00-\u9fa5]{0,}$
2 英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
3 长度为3-20的所有字符:^.{3,20}$
426个英文字母组成的字符串:^[A-Za-z]+$
526个大写英文字母组成的字符串:^[A-Z]+$
626个小写英文字母组成的字符串:^[a-z]+$
7 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
8 由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
9 中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
10 中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
11 可以输入含有^%&',;=?$\"等字符:[^%&',;=?$\x22]+
12 禁止输入含有~的字符:[^~\x22]+


三、特殊需求表达式

1 Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
2 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
3 InternetURL[a-zA-z]+://[^\s]*^https://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
4 手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
5 电话号码("XXX-XXXXXXX""XXXX-XXXXXXXX""XXX-XXXXXXX""XXX-XXXXXXXX""XXXXXXX"和"XXXXXXXX)^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$ 
6 国内电话号码(0511-4405222021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
7 身份证号:
		1518位身份证:^\d{15}|\d{18}$
		15位身份证:^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$
		18位身份证:^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$
8 短身份证号码(数字、字母x结尾)^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$
9 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线)^[a-zA-Z][a-zA-Z0-9_]{4,15}$
10 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线)^[a-zA-Z]\w{5,17}$
11 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间)^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$ 
12 日期格式:^\d{4}-\d{1,2}-\d{1,2}
13 一年的12个月(0109112)^(0?[1-9]|1[0-2])$
14 一个月的31(0109131)^((0?[1-9])|((1|2)[0-9])|30|31)$ 
15 钱的输入格式:
16 1.有四种钱的表示形式我们可以接受:"10000.00""10,000.00", 和没有 "分""10000""10,000"^[1-9][0-9]*$ 
17 2.这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$ 
18 3.一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$ 
19 4.这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$ 
20 5.必须说明的是,小数点后面至少应该有1位数,所以"10."是不通过的,但是 "10""10.2" 是通过的:^[0-9]+(.[0-9]{2})?$ 
21 6.这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$ 
22 7.这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$ 
23 8.13个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$ 
24 备注:这就是最终结果了,别忘了"+"可以用"*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
25 xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
26 中文字符的正则表达式:[\u4e00-\u9fa5]
27 双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
28 空白行的正则表达式:\n\s*\r (可以用来删除空白行)
29 HTML标记的正则表达式:<(\S*?)[^>]*>.*?|<.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
30 首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
31 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
32 中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
33 IP地址:\d+\.\d+\.\d+\.\d+ (提取IP地址时有用)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Dominator945

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

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

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

打赏作者

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

抵扣说明:

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

余额充值