正则表达式详细笔记和代码实例

正则表达式

正则表达式三个常用类

  • 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 是一个非常强制异常类,它表示一个正则表达式模式中的语法错误。

正则表达式API

package cn.itcast.regexp;


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

/*
 * 体验正则表达式的为例,给我们文本 处理带来哪写便利
 * */
public class RegexpDemo01 {
    public static void main(String[] args) {
        // 假设我们使用
        String content = "Apache Hive是一款建立在Hadoop之上的开源数据仓库系统," +
                "可以将存储在Hadoop文件中的结构化,半结构化数据文件映射为一张数据库表," +
                "基于表提供了一种类似SQL的查询模块,称为Hive查询语言(HQL),用于访问和" +
                "分析存储在Hadoop文件中的大型数据集。";

        // 需求提取字符串中所有的英文单词
        // 1,传统方法,说你遍历方式,代码量大,效率不高
        // 2 .正则表达式技术

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

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

package cn.itcast.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)三个版本:J2ME (Java2 Micro版,Java2平台" +
                "的微型版“+”),用于移动、无线和资源有限的环境;J2SE (Java 2 Standard Edition, Java " +
                "2平台的“+”标准版本,应用于桌面环境;在基于Java的应用服务器上,J2EE (Java 2 enterprise" +
                " Edition, Java 2 platform, enterprise Edition)应该是3443中的“+”。Java 2平台的发布" +
                ",是Java开发过程中最重要的里程碑之一, 9889标志着Java应用的开始普及。";
        // 目标:匹配所有四个数字
        // 说明
        // 1、\\d表示一个任意的数字
        String regStr = "(\\d\\d)(\\d\\d)";
        // 2、创建一个模式对象[即正则表达式对象]
        Pattern pattern = Pattern.compile(regStr);
        // 3、创建匹配器
        // 说明:创建匹配器matcher,按照正则表达式的规则去匹配content字符串
        Matcher matcher = pattern.matcher(content);
        // 4.开始匹配
        /*
        *  match.find()完成任务(考虑分组)
        * 什么事分组,比如(\\d)(\\d),正则表达式中有() 表示分组 ,第一个()表示第一组,第二个小括号表示第二组....
        * 1.更苦指定的规则,定位满足规则的子字符串(比如1998)
        * 2.找到后,将子字符串的开始索引记录到matcher对象的属性 int[] groups;
        *   groups[0] = 0, 把该子字符串的结束的索引记录到groups[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、根据 groups[0]=0 和groups[1]=4 的记录的位置,从content开始截取子字符串返回
        * 就是[0,4) 包含 0 但是不包含索引为4的位置
        *
        * 如果再次执行find方法,仍然按照上面的执行
        *
        *
        * */
        while (matcher.find()) {
            System.out.println("找到:" + matcher.group(0));
            System.out.println("第1组()匹配到的值=" +matcher.group(1));
            System.out.println("第2组()匹配到的值="+matcher.group(2));
            // System.out.prinltn(matcher.group(3));这里是会报错的,因为没有第三组,所以在取第三组的时候会报错
            /*
            这里group(1)表示返回的是第一组,第一组是指,在正则表达式第一个括号匹配的的值的
            索引,group(2)表示第二组,group(0)表示没有分组,也就是在没有括号的情况下取的正
            则表达式匹配到的一个整体
            */ 
        }
    }
}

/*
总结 :如果正则表达式有() 即分组,取出匹配的字符串规则如下
	group(0) 表示匹配到的子字符串
	group(1) 表示匹配到的整体的子字符串的第一组字串
	group(2) 表示匹配到的子字符串的第2组字符串
	.....但是分组的数不能越界.
*/

正则表达式语法

基本介绍

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

  • 限定符
  • 选择匹配符
  • 分组组合和方向引用符
  • 特殊字符
  • 定位符
元字符-转义号\
  • \\符号-说明:在我们使用正则表达式取检索某些特殊字符的时候,需要用到转义符号,否则检索不到结果,甚至会报错的。案例:用 取匹配“ a b c 取匹配“abc 取匹配abc(” 会怎样,用(取匹配“abc$"会怎样?
  • 再次提示:在java的正则表达式中,两个\代表其他语言中的一个\
  • 需要用到转义符号的字符有以下:. * + ( ) $ / \ ? [ ] ^ { }

案例

public class Regexp02{
   public static void main(String[] args){
       String content = "abc$(abc(123(";
       // 匹配(
       String regStr = "\\(";
       Pattern pattern = Pattern.compile(regStr);
       Matcher matcher = pattern.matcher(content);
       
       while(matcher.find()){
           System.out.println("找到"+matcher.group(0));
       }
   }
}
元字符-字符匹配符
符号 含义 实例 解释 匹配输入
[ ] 可接收的字符列表 [efgh] e、f、g、h中的任意1个字符
[^] 不接收的字符列表 [^abc] 除a、b、c之外的任意1个字符,包括数字和特殊符号
- 连字符 A-Z 任意单个大写字母
. 匹配\n以外的任何字符 a…b 以a开头,b结尾,中间包括2个任意字符的长度为4的字符串 aaab,aefb
\\d 匹配单个数字字符,相当于[0-9] \\d{3}(\\d)? 包含3个或4个数字的字符串,?表示有0个或1个数字 123,9876
\\D 匹配单个非字符字符,相当[^0-9] \\D(\\d)* 以单个非数字字符开头,后接任意个数字字符串 a、A342
\\w 匹配单个数字,大小写字母字符,相当于[^0-9a-zA-z] \\d{3}\\w{4} 以至少1个非数字字母开头的长度为7的数字字母字符串 234abcd、12345Pe
\\W 匹配单个非数字,大小写字母字符,相当于[^0-9a-zA-Z] \\w+\\d{2} 以至少1个非数字字母字符开头,2个数字字符结尾的字符串 #29、#?@10
\\s 匹配任何空白字符(空格,制表符,等 )
\\S 匹配任何非空字符

案例:

package cn.itcast.regexp;


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

public class RegExp03 {
    public static void main(String[] args) {
        String content = "allc8ab_cA\n BC@";
        // String regStr = "[a-z]";//匹配 a-z 之间任意一个字符一个字符
        // String regStr = "[A-Z]";//匹配 A-Z 之间任意一个字符一个字符
        // String regStr = "abc";//匹配 abc 字符串[默认区分大小写]
        // String regStr = "(?i)abc"; //匹配 abc 字符串
        // String regStr = "[abcd]"; //匹配abcd任意一个字符
        // String regStr = "\\D"; //匹配 不在0-9的任意一个字符
        // String regStr = "\\w"; //匹配 任意字母和数字,下划线
        // String regStr = "\\W"; //匹配 处理字母和数字,下划线
        // String regStr = "\\s"; //匹配 任何空白字符
        // String regStr = "\\S"; //匹配 任何空白字符
        String regStr = "."; //匹配 任何空白字符


        // 说明
        //1.当川建安Pattern对象时,指定 Pattern.CASE_INSENSITIVE,表示匹配是不区分字母大小写,

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

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

    }
}

[^a-z] 说明:

[^a-z]表示可以匹配不是a-z中的任意一个字符

[^A-Z]表示可以匹配不是A-Z中的任意一个字符。

[^0-9]表示可以匹配不是0-9中的任意一个字符。

这个就不举例说明了。

元字符-选择匹配符

在匹配某个字符串的时候是选择性的,即:既可以匹配这个,又可以匹配那个,这时你需要用到选择匹配符 |

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

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

/*
* 选择匹配符
* */
public class Regexp04 {
   public static void main(String[] args){
       String content = "hanshunping 就 寒冷";
       String regStr = "han|就|寒";
       Pattern pattern = Pattern.compile(regStr);
       Matcher matcher = pattern.matcher(content);

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

元字符-限定符

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

符号 含义 实例 说明 匹配输入
* 指定字符重复0次或n次(无要求)零到多 (abc) 仅包含任意个abc的字符串,等效于\w* abc/abcabcabc
+ 指定字符重复1次或n次,1到多 m+(abc)* 以至少1个m开头,后接任意个abc的字符串 m,mabc,mabcabc
? 指定字符重复0次或1次(最多1次) m+abc? 以至少1个m开头,后接ab或abc的字符串 mab,mabc
{n} 只能输入n个字符 [abcd]{3} 由abcd中字母组成的任意长度3的字符串 abc,dbc,adc
{n,} 指定至少n个匹配 [abcd]{3,} 由abcd中字母组成的任意长度不小于3的字符串 aab、dbc、aaabdc
{n, zm} 指定至少n个但不多于m个匹配 [abcd][3,5] 又abcd中字母组成的任意长度不小于3,不大于5的字符串 abc,abcd,aaaaa,bcdab
案例
package cn.itcast.regexp;

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

/*
* 演示限定符的使用
* */
public class Regexp05 {
   public static void main(String[] args) {
       String content = "a1111111aaaaaa1hello";
       // a{3},1{4},(\\d){2}
       // String regStr = "a{3}"; // 表示匹配 aaa
       // String regStr = "1{3}"; // 表示匹配 1111
       // String regStr = "\\d{2}"; // 表示匹配 两位的任意数字字符

       // 细节:java匹配默认贪婪匹配,即尽可能匹配多的
       // String regStr = "a{3,4}"; // 表示匹配 3个a最多4个a

       // String regStr = "\\d{3,4}"; // 表示匹配 4个任意数字或3个任意数字

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

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

       // 样式?的使用,遵守贪婪匹配
       // String regStr = "a1?";    //匹配0个或者多个1
       String regStr = "a1?";    //匹配0个或者多个1


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

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

元字符-定位符

  • 定位符,规定要匹配的字符串出现的位置,比如在字符串的开始还是在结束的位置,这个也是相当有用的,必须掌握
符号 含义 实例 说明 匹配输入
^ 指定其实字符 1+[a-z] 已至少1个数字开头,后接任意个小写字母的字符串 123,6aa,555edf
$ 指定结束字符 2\\-[a-z]+$ 以1个数字开头后接连字符“-”,并以至少1个小写字母结尾的字符串 1-a
\\b 匹配目标字符串的边界 han\\b 这里说的字符串的边界指的是子串间有空格,或者目标字符串的结束位置 hanshunping sphan nnhan
\B 匹配目标字符存的非边界 han\\b 和\b的含义刚刚相反 hanshunping sphan nnhan
案例
package cn.itcast.regexp;

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

/*
* 演示定位符的使用
* */
public class Regexp06 {
   public static void main(String[] args){
       // String content = "123-abc";
       String content = "hanshunping hansphan\n nnhan";

       //以至少1个数字开头,后接任意个小写字母的字符串
       // String regStr = "^[0-9]+[a-z]*"; // 表示匹配以数字开头1到多个,结尾字母0到多个
       // String regStr = "^[0-9]+[a-z]+$"; // 表示以至少1个数字开头,必须以至少一个小写字母结束
       // String regStr = "^[0-9]+\\-[a-z]+$"; // 表示以至少1个数字开头,必须以至少一个小写字母结尾,同时中间还要有一个-
       // String regStr = "han\\b"; // 表示要匹配边界的han,[这里的边界是指:被匹配的字符串的最后,也可以是空格的子字符串的后面]
       String regStr = "han\\B"; // 跟上面是完全相反的,匹配开头且后面没有空格或空格制表符的字符
       Pattern pattern = Pattern.compile(regStr);
       Matcher matcher = pattern.matcher(content);

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

捕获分组

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

案例:

package cn.itcast.regexp;

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

public class Regexp07 {
   public static void main(String[] args) {
       String content = "hanshunping s4343 nn4648han";
       // String regStr = "\\d{4}"; // 匹配4个整数

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

       // String regStr = "(\\d\\d)(\\d\\d)";  // 匹配2个组的数字,两个组分别是2个数字
       // String regStr = "(\\d\\d)(\\d)(\\d)";  // 匹配4个数字,分为3个组,第一个数2个数字,第2,3个组1个数字

       //命名分组:即可以给分组取名
       String regStr = "(?\\d\\d)(?\\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("第2个分组的内容:" + matcher.group(2));
           System.out.println("第3个分组的内容:" + matcher.group(3));

           // 使用分组名称来获取字符
           System.out.println("第1个分组的内容[通过名称获取]:" + matcher.group("g1"));
           System.out.println("第2个分组的内容[通过名称获取]:" + matcher.group("g2"));

       }
   }
}

特别分组

常用分组构造形式 说明
(?:pattern) 匹配pattern但是不捕获该匹配的子表达式,即他是一个非捕获匹配,不存在存储供以后使用的匹配。这对于用or字符(|)组合模式不见的情况很有用。例如,“industr(?:y|ies)是比’industry|industries’更经济的表达式
(?!pattern) 该表达式匹配不春雨匹配pattern的字符串的起始点的搜索字符串,它是一个捕获匹配。例如,“Windows(?=95|98|NT|2000)“匹配 “Windows 2000”中的“Windows”,但是不“Windows 3.1"中的”Windows”。
(?!pattern) 该表达式匹配不处于匹配 pattern的字符串的起始点的搜索字符串。它是一个非捕获匹配,例如“Windows(?!95|98|NT|2000)“匹配”Windows 3.1"中的“Windows”,但不匹配“Windows3.1"向后的”Windows"
案例
package cn.itcast.regexp;

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

public class Regexp08 {
   public static void main(String[] args) {
       String content = "hello韩顺平教育 jack韩顺平老师 韩顺平同学hello";
       // String regStr = "韩顺平教育|韩顺平老师|韩顺平同学";
       // 上面的写法可以等价非捕获分组

       // (?:pattern)
       // String regStr = "韩顺平(?:教育|老师|同学)"; // 不建议这样写,因为这看似一个分组,
       // 但是并不会捕获分组,所以如果使用matcher.group(1)捕获会报错的

       //(?!pattern)
       // String regStr = "韩顺平(?=教育|老师)";  // 非捕获,不能使用matcher.group(1)获取,或报错

       //(?!pattern)
       String regStr = "韩顺平(?!教育|老师)";  //匹配不是韩顺平教育和韩顺平老师的韩顺平,是其他的韩顺平 非捕获,不能使用matcher.group(1)获取,或报错

       // 创建模式对象
       Pattern pattern = Pattern.compile(regStr);
       // 创建匹配器对象
       Matcher matcher = pattern.matcher(content);

       // 循环遍历匹配到的字符并打印
       while (matcher.find()) {
           System.out.println("找到:" + matcher.group(0));
       }
   }
}

取消贪婪匹配

  • 可以在任意贪婪匹配符后面加上?可以取消贪婪匹配
package cn.itcast.regexp;

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

public class Regexp09 {
   public static void main(String[] args) {
       String content = "hello111111 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));
       }
   }
} 

应用案例

  • 对字符串进行如下验证
  1. 汉字

  2. 邮政编码

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

  3. qq号码

    要求:是1-9开头的11位数,比如2693024032

  4. 手机号码

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

  5. URL:如图:https://www.bilibili.com/video/BV1Eq4y1E79W/?p=16&spm_id_from=pageDriver&vd_

代码:

package cn.itcast.regexp;

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

/*
* 正则表达式的应用实例
* */
public class Regexp10 {
   public static void main(String[] args) {
       // String content = "韩顺平教育";
       // String content = "123890";
       // String content = "2693024202";
       // String content = "15216173555";
       String content = "https://cwiki.apache.org/confluence/display/Hive//GettingStarted";
       // 汉字
       // String regStr = "^[\u0391-\uffe5]$";  // 表示在这个编码值内的字符就是汉字

       // 邮政编码  // String regStr = "^[1-9]\\d{5}$";

       //qq号码
       //String regStr = "^[1-9]\\d{4,9}$";

       // 手机号
       // String regStr = "^1[3|4|5|8]\\d{9}$";

       // url
       /*
        * 思路:
        * 1、想去顶url的开始部分 https:// | http://
        * 2、然后通过 ([\w-]+\.)+[\w-]+匹配www.bilibili.com
        * 3、/video/BV1Eq4y1E79W/....  匹配(\\/[\\w-?=&/@#.]*)?$
        * */22
       // 注意:[.] 表示匹配就是.本身
       String regStr = "^((https|http)://)([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/@#.]*)?$";


       // 创建模式对象
       Pattern pattern = Pattern.compile(regStr);

       // 创建匹配对象
       Matcher matcher = pattern.matcher(content);

       // 获取到的匹配字符
       if (matcher.find()) {
           System.out.println("满足格式");
           System.out.println(matcher.group(0));
       } else {
           System.out.println("不满足格式");
       }
       // 这里如果使用Patternmatches 整体匹配比较简洁
       System.out.println(Pattern.matches(regStr,content));
   }
}

.在中括号里面是不需要进行转义的,任何符号都是,不需要转义

package cn.itcast.regexp;

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

public class Regexp11 {
   public static void main(String[] args) {
       String content = "hello abc hello";
       // String regStr = "[.]]";  // 匹配字符.
       // String regStr = "."; // 匹配所有字符
       String regStr = "?"; // 匹配单独的字符?
       Pattern pattern = Pattern.compile(regStr);
       Matcher matcher = pattern.matcher(content);
       while (matcher.find()) {
           System.out.println("找到:" + matcher.group(0));
       }
   }
}
Pattern.matches方法的作用
package cn.itcast.regexp;

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

public class Regexp11 {
   public static void main(String[] args) {
       String content = "hello abc hello";
       // String regStr = "[.]]";  // 匹配字符.
       String regStr = "."; // 匹配所有字符
       Pattern pattern = Pattern.compile(regStr);
       Matcher matcher = pattern.matcher(content);
       while (matcher.find()) {
           System.out.println("找到:" + matcher.group(0));
       }

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

Matcher.start方法和Matcher.end方法的作用

package cn.itcast.regexp;

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

/*
* Matcher 类的常用方法
* */
public class MatcherMathod {
   public static void main(String[] args) {
       String content = "hello edu jack tom hello hspedu 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("韩顺平教育");
       // 如果想要替换原来字符串的话使用content接收
       content = matcher.replaceAll("韩顺平教育");
       //System.out.println("newContent="+ newContent);
       System.out.println("content=" + content);
   }
}

分组、捕获、反向应用的关系

需求:
给你一段文本,请你找出所有四个数字连在一起的子串,并且这四个数字要满足①第一位与第四位相同②第2位于第3位相同,比如 1221,5775,…

分组:

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

捕获

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

反向引用

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

案例

package cn.itcast.regexp;

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

/*
* 反向引用
* */
public class Regexp12 {
   public static void main(String[] args) {
       String content = "h1234e9875llo33333 12321-333999111jack tom155111 jack22 yyy4343434 xxx";
       // String regStr = "(\\d)\\1";
       // String regStr = "(\\d)\\1{4}";
       // tring regStr = "(\\d)(\\d)\\2\\1";
       /*
        * 请在字符串中检索商品编号,形式如:12321-333999111 这样的号码,
        * 要求满足前面是一个五位数,然后一个-号,然后是一个九位数,连续的每三位要相同
        * */
       String regStr = "(\\d)(\\d)\\d\\2\\1-(\\d)\\3{2}(\\d)\\4{2}(\\d)\\5{2}";

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

案例使用反引用替换掉多于的字符

package cn.itcast.regexp;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
5
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) 使用 (.)\\+
       // (2) 使用反向引用$1 来替换匹配到的内容


       // 注意:因为正则表达式变化,所以需要重置matcher
       pattern = Pattern.compile("(.)\\1+");
       matcher = pattern.matcher(content);
       while (matcher.find()) {
           System.out.println("找到=" + matcher.group(0));
       }
       System.out.println("---------------");
       // 使用反向引用$1来替换正则表达式说匹配到的所有字符
       String contern = matcher.replaceAll("$1");
       System.out.println("content" + contern);

       // 3.使用一条语句 取去掉重复的文字我我要学学学学编程java!
       Pattern.compile("(.)\\1+").matcher(content).replaceAll("$1");
       System.out.println("content" + contern);
   }
}
案例
package cn.itcast.regexp;

public class Regexp14 {
   public static void main(String[] args) {
       String content = "在2000年5月,JDK1.3, JDK1.4和J2SE1。3款已经发布,几周后的\n" +
               "赢得了苹果Mac OSX工业标准的支持。2001年9月24日,J2EE1。三个头发\n" +
               "2002年2月26日,J2SE1.4. 因为Java的计算能力已经提高了\n";

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

       // 要求 验证一个手机号,要求必须是以138 139 开头的
       content = "13883739455";

       if (content.matches("1(38|39)\\d{8}")) {
           System.out.println("验证成功");
       } else {
           System.out.println("验证失败");
       }

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

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

       String  content = "[email protected]";
       String regStr = "^[\\w-]+@([a-zA-Z]+\\.)+[a-zA-Z]+";

       // 1.String 的 matches 是整体匹配
       if(content.matches(regStr)){
            System.out.println("匹配成功");
       }else{
           System.out.println("匹配失败");
       }

   }
} 
package cn.itcast.regexp;

public class Homework02 {
   public static void main(String[] args) {
       // 要求验证是不是整数或者小数
       // 提示:这个题要考虑正数和负数
       // 比如:123 -345 34.89 -87.9 -0.01 0.45 等

       /*
       * 1.先写出简单的正则表达式
       * 2.在逐步的完善[根据各种情况来完善]
       * */
       String content = "37874554545454455454";
       String regStr = "^[-+]?([1-9]\\d*|0)(\\.)?(\\d+)?$";

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

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

public class Regexp16 {
   public static void main(String[] args) {
       String content = "http://www.sohu.com:8080/abcfd/dfd/fdf//fd/index.heml";
       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("匹配失败");
       }
   }
}

  1. 0-9 ↩︎

  2. 0-9 ↩︎

你可能感兴趣的:(正则表达式)