yuluo829 发表于 2022-1-16 13:47

正则表达式(regular expression [regExp])

# 正则表达式(regular expression )

## 介绍

### 概念

​        一个正则表达式,就是用某种模式去匹配字符串的一个公式。许多语言都提供了对正则表达式的支持

### 正则表达式初体验

> 1, 提取某段文字中的所有英语单词

> 2, 提取数字

> 3, 提取数字和英语单词

```java
package com.company.Regexp;

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

public class RegexpText01 {
    public static void main(String[] args) {

      //文本信息
      String content = "Linux,全称GNU/Linux,是一种免费使用和自由传播的类UNIX操作系统," +
                "其内核由林纳斯·本纳第克特·托瓦兹于1991年10月5日首次发布,它主要受到Minix和Unix" +
                "思想的启发,是一个基于POSIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行" +
                "主要的Unix工具软件、应用程序和网络协议。它支持32位和64位硬件。Linux继承了Unix" +
                "以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。Linux有上百种不同的发行版," +
                "如基于社区开发的debian、archlinux,和基于商业开发的" +
                "Red Hat Enterprise Linux、SUSE、Oracle Linux等。\n" +
                "2021年6月,根据Linux 5.14刚刚进入合并队列的char-misc-next提交," +
                "Linux 5.14正式移除了RAW驱动";

      //找出其中的全部英语单词
      //找出百度热搜的标题:(///S*)
      //传统方法:使用遍历方式,代码量大,效率不高
      //正则表达式:
      /**
         * 1,先创建一个Pattern对象,模式对象,可以理解成一个正则表达式对象
         * 2,创建一个匹配器对象
         * 3,开始循环匹配
         */
      Pattern patter = Pattern.compile("(+)|(+)");
      //匹配数字时,
      //数字+英文单词 (+)|(+)
      //按照patter(模式/样式)。到content文本中匹配,找到true。否false
      Matcher matcher = patter.matcher(content);
      while (matcher.find()) {
            //匹配内容,文本放到matcher.group(); 中
            System.out.println("找到:" + matcher.group(0));
      }
    }
}

```

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

> 找出文本中的所有数字子串

> 验证电子邮件和手机号码格式

> 正则表达式技术是对字符串进行模式匹配的技术

## 分析Java正则的底层实现原理

```java
package com.company.Regexp;

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

public class RegexpText02 {
    public static void main(String[] args) {
      //文本信息
      String content = "Linux,全称GNU/Linux,是一种免费使用和自由传播的类UNIX操作系统," +
                "其内核由林纳斯·本纳第克特·托瓦兹于1991年10月5日首次发布,它主要受到Minix和Unix" +
                "思想的启发,是一个基于POSIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行" +
                "主要的Unix工具软件、应用程序和网络协议。它支持32位和64位硬件。Linux继承了Unix" +
                "以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。Linux有上百种不同的发行版," +
                "如基于社区开发的debian、archlinux,和基于商业开发的" +
                "Red Hat Enterprise Linux、SUSE、Oracle Linux等。\n" +
                "2021年6月,根据Linux 5.14刚刚进入合并队列的char-misc-next提交," +
                "Linux 5.14正式移除了RAW驱动";

      //目标:匹配所有四个数字
      //说明
      //1, \\d 表示一个数字
      String regStr = "\\d\\d\\d\\d";
      //2, 创建模式对象
      Pattern patter = Pattern.compile(regStr);
      //3, 创建匹配器
      //说明:创建匹配器matcher, 按照正则表达式的规则去匹配content字符串
      Matcher matcher = patter.matcher(content);
      //4, 开始匹配
      while (matcher.find()) {
            System.out.println("找到:" + matcher.group(0));
      }
    }
}
find()和group()的实现原理是什么?
```

##### matcher.find() 完成的任务:

        1. 根据指定的规则,定位满足规则的子字符串
        2. 什么是分组,(//d//d)(//d//d),正则表达式中有(),表示分组。第一个()表示第一组,以此类推……
        3. 找到后,将子字符串的开始索引记录到matcher对象的属性int[] group,groups = 0, 把该子字符串结束的索引+1的值记录到gruops = 4
        4. 同时记录oldLast的值为子字符串结束的索引+1的值即4,下次执行find的时候,从4开始匹配

##### matcher.group():完成的任务:

```java
//JDK源码:
public String group(int group) {
    if (first < 0)
      throw new IndexOutOfBoundsException("No match found");
    if (group <0 || group > groupCount())
      throw new IndexOutOfBoundsException("No group" + group);
    if ((groups == -1) || (groups == -1)) {
      return null;
    }
    return getSubSequence(groups, groups).toString;
}
```

1. 根据groups 和 groups = 4的记录位置,从content开始截取子字符串返回就是包含0但是不包含索引为4的位置
2. 关于groups数组的理解:比如匹配(//d//d)(//d//d),匹配四位数的数字,第一组的值即找到1998。group = 19; group = 98
3. 如果正则表达式分组(),即分组,则匹配规则如下

group:表示匹配到的子字符串

group:表示匹配到的子字符串的第一组子串

group:表示匹配到的子字符串的第二组子串

但是匹配到的子字符串不能越界

## 正则表达式语法

### 正则转义符

#### 分类

想要灵活的使用正则表达式,必须了解其中各种元字符(Metacharacter)的功能,从功能上大致分为

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

#### 转义号 \\\

\\\:转义字符,表示一个 \ ,

在其他语言中,\表示一个反斜杠

```java
package com.company.Regexp;

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

/**
* 转义符的使用
*/

public class RegexpText03 {
    public static void main(String[] args) {

      String content = "abc$(abc(123(";

      //匹配(
      String regStr = "\\(";
      Pattern patter = Pattern.compile(regStr);
      Matcher matcher = patter.matcher(content);

      //开始匹配
      while (matcher.find()) {
            System.out.println("找到" + matcher.group(0));
      }
    }
}

```

例如:要匹配 . 的正则为"\\\\.", 而不是”.“ 。

#### 字符匹配符

[ ]:可接受的字符列表

eg::e, f, g, h 中的任意一个字符

[^]:不可接受的字符列表

eg:除a, b, c 之外的任意一个字符,包括数字和特殊符号

\- :连字符

eg:A-Z:任意的单个大写字母

\. :匹配除\n以外的任何字符,如果要匹配 . 要用转义符

eg:a..b : 以a开头,b结尾,中间包括2个任意字符的长度为4的字符串,aaab,a67b,a%¥b

\\\d : 匹配单个的数字字符,相当于

eg:\\\d{3}(\\\d)? 包含3个或者4个数字的字符串,123,4567

\\\D:匹配单个非数字字符串,相当于[\^0-9]

eg:\\\D(\\\d)\*, 以单个非数字字符开头,后接任意个数字字符串,a、A342、b45678

\\\w:匹配单个数字,大小写字母字符,相当于[-9a-zA-Z]

eg:\\\d{3}\\\w{4}, 以3个数字字符开头的长度为7的数字字母字符串,234abcd、12345pe

\\\W:匹配单个非数字,大小写字母字符,相当于[\^0-9a-zA-Z]

eg:\\\W+\\\d{2}, 以至少1个非数字字母字符开头,2个数字字符结尾的字符串,#29、#@!10

\\\s: 匹配任何空白字符,(空格,制表符等)

\\\S: 相当于对s取反,匹配任何非空白字符

Java的正则表达式是区分字母大小写的,如何实现不区分大小写:

1. (?i)abc 表示abc都不区分大小写

2. a(?i)bc表示bc都不区分大小写

3. a((>i)b)c表示b都不区分大小写

4. Pattern pat = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE); 创建正则表达式对象的时候,加入CASE_INSENSITIVE(不敏感,不区分大小写)

   ```java
   package com.company.Regexp;
   
   import java.util.regex.Matcher;
   import java.util.regex.Pattern;
   
   /**
    * 演示字符匹配法符使用
    */
   
   public class RegexpText04 {
       public static void main(String[] args) {
         String content = "abcd//C97ABCDy";
         //String regStr = "";//匹配a-z之间任意一个字符
         //String regStr = ""; //匹配任意一个A-Z的大写字符
         //String regStr = "abc";//默认只匹配abc,而且区分大小写
         //String regStr = "(?i)abc";//不区分大小写匹配ABC/abc
         //String regStr = "[^a-z]";//匹配不在a-z之间任意一个字符
         //String regStr = ""; //匹配在abcd中的任意一个字符
         String regStr = "\\w"; //匹配大小写英文字母,数字,下划线
   
         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.company.Regexp;

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

/**
* 选择匹配符的使用
*/

public class RegexpText05 {
    public static void main(String[] args) {
      String content = "韩张三 zhangsan";

      String regStr = "san|韩|张";

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

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

#### 限定符

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

\* : 指定字符重复0此或n此(与具体要求)

eg:(abc*), 仅包含任意个abc的字符串,等效于\w\*, abc、abcabcabc

+:指定字符重复次或者n次(至少1次)

eg:m+(abc)\*, 以至少一个m开头,后接任意个abc的字符串,m、mabc、mabcabc

?:指定字符重复0次或者1次(最多一次)

eg:m+abc?, 以至少一个m开头,后接ab或者abc的字符串,mab、mabc、mmmab、mmabc

{n}:只能输入n个字符

eg:{3}, 以abcd组成的任意长度为3的字符串,abc、dbc、acd

{n,}:指定至少n个匹配

eg:{3,}, 由abcd中字母组成的任意长度不小于3(>=3)的字符串,aab、dbc、aaabdc

{n,m}:只当至少n个但不多于m个匹配

eg:{3,5},由abcd中字母组成的任意长度不小于3,不大于5(5>=x>=3)的字符串,abc、abcd、badab、badca

```java
package com.company.Regexp;

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

/**
* 演示限定符的是使用
*/

public class RegexpText06 {
    public static void main(String[] args) {
      String content = "11111111a21aaaaaahello";

      //String regStr = "a{3}";//找出三个a
      //String regStr = "1{4}";
      //String regStr = "\\d{2}";//表示两位的任意数字字符
      /*
      java的正则匹配默认是贪婪匹配,尽可能匹配多的字符串
         */
      //String regStr = "a{3,4}";
      //String regStr = "\\d{3,5}";

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

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

      //? 的使用
      String regStr = "a1?";//匹配a或者a1

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

      while (matcher.find()) {
            System.out.println(matcher.group(0));
      }
    }
}

```

#### 元字符

^: 指定起始字符,^+\*,以至少1个数字开头,后接任意个小写字母,123、6aa、555edf

\$:指定结束字符,^\\\\-+\$,以1个数字开头后接连字符”-“,并以至少一个小写字母结尾的字符串,1-a

\\\b:匹配目标字符串的边界,han\\\b,这里的字符串的边界指的是子串间有空格,或者是目标字符串的结束位置,hansunping、sphan、nnhan

\\B:匹配目标字符串的边界,han\\\B,和\b的含义相反,hanshunping,sphan,nnhan

```java
package com.company.Regexp;

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

/**
* 定位符的使用
*/

public class RegexpText07 {
    public static void main(String[] args) {
      //String content = "123abc";
      String content = "hanshunping abchan defghan";

      //String regStr = "^+*";
      //a123abc, 匹配失败

      //String regStr = "^++$";
      //以a-z的其中一个结尾

      String regStr = "han\\b";
      //这里的边界值得是字符串的最后,或者是空格的前面字符串的末尾

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

      while (matcher.find()) {
            System.out.println(matcher.group(0));
      }
    }
}

```

#### 分组

1. 常用分组

常用分组构造形式

(pattern):非命名捕获,捕获匹配的子字符串。编号为零的第一个捕获是由整个正则表达式模式匹配的文本,其他捕获结果则根据左括号的顺序从1开始自动编号。

(? <name> pattern):命名捕获,将匹配到的子字符串捕获到一个组名称或编号名称中。用于name的字符串不能包含任何标点符号,并且不能以数字开头。可以使用单引号替代尖括号,例如(?'name')

```java
package com.company.Regexp;

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

/**
*分组
*/

public class regexpText08 {
    public static void main(String[] args) {
      String content = "hanshunping s7789 nn1189han";

      //String regStr = "(\\d\\d)(\\d\\d)";//,匹配四个数字的字符串,相当于d{4};
      //非命名分组
      //matcher.group(0);获取整个的字符串
      //matcher.group(1);获取分组的第一个子字符串
      //matcher.group(2);获取分组的第二个子字符串
      //一个括号是一个组
      //第一个分组是77,第二个分组是89

      //命名分组:即可以给分组取名
      String regStr = "(?<g1>\\d\\d)(?<g2>\\d\\d)";

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

      while (matcher.find()) {
            System.out.println("找到" + matcher.group(0));
            //System.out.println("第一个分组内容" + matcher.group(1));
            //System.out.println("第二个分组内容" + matcher.group(2));
            System.out.println("第一个分组内容[通过组名]" + matcher.group("g1"));
            System.out.println("第二个分组内容[通过组名]" + matcher.group("g2"));
      }
    }
}

```

#### 特别分组

(?:pattern):匹配pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。但这对于“or”字符(|)组合模式部件的情况很有用。例如:'industr(?:y|ies)'是比,'indeustry|industries'更经济的表达式

(?=pattern):它是一个非捕获匹配。例如,'Windwos(?=95|98|NT|2000)' 的匹配 “Windows 2000” 中的 “Windows 3.1” 中的"Windows"

(?!patter):该表达式匹配不处于匹配pattern的字符串的起始点的搜索字符串。他是一个非捕获匹配。例如,'Windwos(?=95|98|NT|2000)' 匹配“Windows 3.1” 中的"Windows",但不匹配 “Windows 2000” 中的 “Windows“。

```java
package com.company.Regexp;

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

/**
*非捕获分组
* 以下三个全为非捕获分组
*/

public class RegexpText09 {
    public static void main(String[] args) {
      String content = "hello中国人民 中国经济abc def中国发展";

      //String regStr = "中国(?:人民|经济)";
      //等价于:String regStr = "中国人民|中国经济";

      //要求查找中国人民,中国发展,中国经济中的中国
      //String regStr = "中国(?=人民|经济)";

      //和(?=pattern)结果相反
      String regStr = "中国(?!人民|经济)";

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

      while (matcher.find()) {
            System.out.println(matcher.group(0));
            //System.out.println(matcher.group(1));
            //非捕获,不能这么操作
      }
    }
}

```

#### 非贪婪匹配

?:当此字符紧随任何其他限定符(\*,+, ?, {n}, {n,}, {n,m})之后时,匹配模式是”非贪心的“。”非贪心的“模式匹配搜索到的,尽可能短的字符串,默认的”贪心“模式匹配搜索到的,尽可能长的字符串。例如在"oooo", "o+?"只匹配单个"o", 而“o+”匹配所有 “o”。

### 正则表达式应用实例

```java
package com.company.Regexp;

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

/**
* 正则表达式应用实例
* 1,验证汉字
* 2,邮政编码是1-9开头的数字,比如123890
* 3,QQ号码   是1-9开头的一个(5位数-19位数),比如12389.134578
* 4,手机号码必须以13,14,15,18开头的11位数。
*/

public class RegexpText10 {
    public static void main(String[] args) {
      //验证汉字
      //String content = "中国人";
      //汉字编码范围之内
      //String regStr = "^[\u0391-\uffe5]+$";

      //邮政编码
      //String content = "744500";
      //String regStr= "^\\d{5}$";

      //QQ号码
      //String content = "14815566";
      //String regStr= "^\\d{4,9}$";

      //手机号码
      String content = "13588886666";
      String regStr= "^1\\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.company.Regexp;

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

/**
* 验证url
*/

public class RegexpText11 {
    public static void main(String[] args) {
      String content = "https://www.bilibili.com/video/BV1Eq4y1E79W?p=17&spm_id_from=pageDriver";

      /**
         * 思路:
         * 确定url的开始部分 https:// | http://
         * regStr = "^((http|https)://)";                                          https://
         * regStr = "^((http|https)://)([\w-]+\.)+";                              https://www.bilibili.
         * regStr = "^^((http|https)://)([\w-]+\.)+[\w-]+$+$";                     https://www.bilibili.com
         * regStr = "^((http|https)://)([\w-]+\.)+[\w-]+(\\/[\\w-?=&/%.]*)?$";       https://www.bilibili.com/video/BV1Eq4y1E79W?p=17&spm_id_from=pageDriver
         */

      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("不满足格式");
      }
    }
}

```

## 正则表达式常用类

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

### Pattern类

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

> Pattern类中的matcher方法
>
> ```java
> package com.company.Regexp;
>
> import java.util.regex.Pattern;
>
> /**
>* matches方法,用于整体匹配,在验证输入的字符串是否满足正则表达式的条件
>* 底层使用Matcher类的matches方法
>*/
>
> public class PatternMethod {
>   public static void main(String[] args) {
>         String content = "hello abc hello, 中国人";
>         String regStr = "hello.*";
>
>         boolean matches = Pattern.matches(regStr, content);
>
>         System.out.println("整体匹配="+ matches);
>   }
> }
> ```

### Matcher类

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

> Matcher的常用方法
>
> ```java
> package com.company.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 jck tom smith hello zgr";
>         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());
>             /**
>            * 第一组hello对应的下标
>            * ===========
>            * 0
>            * 5
>            *
>            * 第二组hello对应的下标
>            * ===========
>            * 24
>            * 29
>            */
>             System.out.println("找到=" + content.substring(matcher.start(), matcher.end()));
>         }
>         //整体匹配方法,常用于去校验某个字符串是否满足某个规则
>         //整体匹配:String regStr = "hello.*"; 返回结果为true;
>         System.out.println("整体匹配" + matcher.matches());
>
>         //完成替换:将zgr替换成中国人
>         regStr = "zgr";
>         pattern = Pattern.compile(regStr);
>         matcher = pattern.matcher(content);
>         //注意:返回的字符串才是替换后的字符串,原来的content不变
>         String newContent = matcher.replaceAll("中国人");
>         System.out.println("newContent=" + newContent);
>   }
> }
>
> ```
>
>

### PatternSyntaxException

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

## 反向引用

### 概念

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

### 应用案例

```java
package com.company.Regexp;

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

/**
*匹配两个连续相同的数字   (\\d)\\1反向引用一次
*匹配五个连续相同的数字   (\\d)\\1{4}反向引用四次
*匹配个位和千位相同,十位和百位相同的数字5225,1551
*在字符串中检索商品编号,如:12321-333999111
*要求满足前面是一个五位数,然后一个-号,然后一个九位数,连续的三位要相同
*/

public class RegexpText12 {
    public static void main(String[] args) {

      String content = "22222 h1234ell7896o jac1551k t12321-333999111om11 jack22 xxx 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
package com.company.Regexp;

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

/**
* 经典的结巴程序
* 把类似:”我……我要……学学学……编程java“;
* 通过正则表达式修改成”我要学编程java“
*/

public class RegexpText13 {
    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,去掉所有重复的字
      /**
         * 思路:
         * 1,使用(.)\\1+
         * 2,使用反向引用$1来替换匹配到的内容
         * 3,使用一条语句去掉重复的字
         * 注意:因为正则表达式变化,所以要重置matcher
         */
//      pattern = Pattern.compile("(.)\\1+");
//      matcher = pattern.matcher(content);
//      while (matcher.find()) {
//            System.out.println(matcher.group(0));
//      }
//
//      content = matcher.replaceAll("$1");
//      System.out.println("content=" + content);

      content = Pattern.compile("(.)\\1+").matcher(content).replaceAll("$1");
      System.out.println(content);
    }
}
```

## 替换分割匹配

### 替换

```java
package com.company.Regexp;

/**
* 替换
*/

public class RegexpText14 {
    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的计算能力有了大幅提升,与J2SE1.3相比,其多了近62%的类和接口。" +
                "在这些新特性当中,还提供了广泛的XML支持、安全套接字(Socket)" +
                "支持(通过SSL与TLS协议)、全新的I/OAPI、正则表达式、日志与断言。" +
                "2004年9月30日,J2SE1.5发布,成为Java语言发展史上的又一里程碑。" +
                "为了表示该版本的重要性,J2SE 1.5更名为Java SE 5.0(内部版本号1.5.0)," +
                "代号为“Tiger”,Tiger包含了从1996年发布1.0版本以来的最重大的更新," +
                "其中包括泛型支持、基本类型的自动装箱、改进的循环、枚举类型、" +
                "格式化I/O及可变参数。";

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

```



### 分割

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



### 匹配

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

## 练习

### 验证整数或者小数

```java
package com.company.Regexp;

/**
* 验证整数或者小数
* 思路:
* 先写出正则表达式
* 然后逐步完善
*/

public class RegexpText15 {
    public static void main(String[] args) {
      String content = "-0.89";
      String regStr = "^[-+]?(\\d*|0)+(\\.\\d+)?$";

      if (content.matches(regStr)) {
            System.out.println("验证成功");
      } else {
            System.out.println("验证失败");
      }
    }
}
```

chishingchan 发表于 2022-1-16 15:38

配合这个软件学习不错!
https://www.chinapyg.com/thread-142225-1-1.html

盘儿净 发表于 2022-1-16 17:40

chishingchan 发表于 2022-1-16 15:38
配合这个软件学习不错!
https://www.chinapyg.com/thread-142225-1-1.html

兄弟能否发转发一个RegexBuddy零售版过来?没有飘云阁的账号。

涛之雨 发表于 2022-1-16 20:05

个人感觉还是PHP,js之类的/regExp/这种形式的比较容易入手一点。。。
毕竟满脸都是转义符有点脑壳疼(然后可以找网页写好正则表达式生成各个语言的代码
推荐个网页https://regex101.com/
支持在线调试正则表达式(没错就是调试,尝试了就知道了),设置里可以调不完全中文。
然后调试完,直接生成各个语言的代码

wzyl 发表于 2022-1-16 21:11

谢谢楼主普及技能知识{:1_893:}

yuluo829 发表于 2022-1-16 21:51

chishingchan 发表于 2022-1-16 15:38
配合这个软件学习不错!
https://www.chinapyg.com/thread-142225-1-1.html

学到了学到了

yuluo829 发表于 2022-1-16 21:52

wzyl 发表于 2022-1-16 21:11
谢谢楼主普及技能知识

互相学习,共同进步,哈哈

yuluo829 发表于 2022-1-16 21:55

涛之雨 发表于 2022-1-16 20:05
个人感觉还是PHP,js之类的/regExp/这种形式的比较容易入手一点。。。
毕竟满脸都是转义符有点脑壳疼(然 ...

收藏了已经

yuluo829 发表于 2022-1-16 22:05

盘儿净 发表于 2022-1-16 17:40
兄弟能否发转发一个RegexBuddy零售版过来?没有飘云阁的账号。

好几次都抢不到邀请码,泪崩

chunhwa 发表于 2022-1-16 22:27

谢谢分享,迟点再看一遍。
页: [1] 2
查看完整版本: 正则表达式(regular expression [regExp])