正则表达式(Java)

正则表达式:

- regular expression => RegExp

1、底层实现 :

1.1 什么是分组:(例如:2023)

1.不分组:\\d\\d\\d\\d

2.分组:(\\d\\d)(\\d\\d),正则表达式中有 () 表示分组,一个括号为一组

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

1.根据指定的规则,定位满足规则的子字符串

2.找到后,将子字符串的开始的索引记录到 matcher 对象的属性 int groups;

a.不分组:(例如:2023)

i.把该子字符串开始位置的索引记录到 groups[0] = 0 中 ,结束的索引+1的值记录到 groups[1] = 4中;

b.分组:(例如:(20)(23))

i.把该子字符串开始位置的索引记录到 groups[0] = 0 中 ,结束的索引+1的值记录到 groups[1] = 4中;

ii.记录 1 组 () 匹配的字符串 groups[2] = 0,groups[3] = 2

iii.记录 2 组 () 匹配的字符串 groups[4] = 2,groups[5] = 4

iv.如果有更多的分组以此类推

3.同时记录 oldLast 的值为子字符串结束位置的索引+1,即下次执行 find 方法时,就从 lodLast 开始

a.例如 groups[0] = 0 和 groups[1] = 4 的记录的位置,oldLast = 4,从 content 开始截取子字符串返回,就是 [0, 4) 左闭右开

b.如果再次执行 find 方法,仍然按上面的执行

1.3 小结:

1.如果正则表达式有 () 即分组

2.取出匹配的字符串规则如下:

a.group(0) 表示匹配到的子字符串

b.group(1) 表示匹配到的子字符串的第一组子串

c.group(2) 表示匹配到的子字符串的第二组子串

d.以此类推,但是不能越界

1.4 例子:

String content = "……";

// 1、\\d 表示一个任意的数字

//String regStr = "\\d\\d\\d\\d";

String regStr = "(\\d\\d)(\\d\\d)";

// 2、创建模式对象[即正则表达式对象]

Pattren pattern = Pattern.compile(regStr);

// 3、创建匹配器

// 说明:创建匹配器 matcher,按照正则表达式的规则去匹配 content 字符串

Matcher matcher = Pattern.matcher(content);

// 4、开始匹配

while(matcher.find()){

    System.out.println("找到:" + matcher.group(0));

    System.out.println("第一组为:" + matcher.group(1));

    System.out.println("第二组为:" + matcher.group(2));

}

2、语法:

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

- \\ 符号 说明:

- 在使用正则表达式去检索某些特殊字符时,需要用到转义字符,否则检索不到结果,甚至报错

- 在 Java 中的正则表达式这个,两个 \\ 代表其他语言中的一个 \

- 需要用到转义符号的字符有:. * + ( ) $ / \ ? [ ] ^ { }

例如:

匹配(:\\(

匹配.:\\.

2.1 限定符

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

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

- 细节:

- 非贪婪匹配和贪婪匹配:

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

String content = "hello111111 ok";

//String regStr = "\\d+"; //默认是贪婪匹配

String regStr = "\\d+?"; 1/非贪婪匹配

Pattern pattern = Pattern.compile(regStr);

Matcher matcher = pattern.matcher(content);

while (matcher.find()) {

    System.out.println("找到: " + matcher.group(0));

}

2.2 选择匹配符

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

符号含义示例解释|匹配 “|” 之前或之后的表达式ab|cdab 或者 cd

2.3 分组组合和反向引用符:

2.3.1 分组、捕获和反向引用的概念:

1.分组:

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

2. 捕获:

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

3.反向引用:

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

2.3.2 捕获分组:

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

// 下面就是非命名分组

// 说明

// 1. matcher.group(0) 得到匹配到的字符串

// 2. matcher.group(1) 得到匹配到的字符串的第 1 个分组内容

// 3. matcher.group(2) 得到匹配到的字符串的第 2 个分组内容

// String regStr = "(\\d\\d)(\\d\\d)";//匹配 4 个数字的字符串

//命名分组: 即可以给分组取名

String regStr = "(?\\d\\d)(?\\d\\d)"; // 匹配 4 个数字的字符串

I

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"));

}

2.3.3 非捕获分组:

常用分组构造形式说明(?:pattern)匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用 "or" 字符(|) 组合模式部件的情况很有用。例如,'industr(?:ylies) 是比 'industry | industries' 更经济的表达式。(?=pattern)它是一个非捕获匹配。例如,'Windows (?=95|98|NT|2000)’ 匹配 "Windows 2000" 中的 "Windows",但不匹配 "Windows 3.1" 中的 "Windows"。(?!pattern)该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配。例如,'Windows (?!9598|NT|2000)' 匹配 "Windows 3.1" 中的 "Windows",但不匹配"Windows 2000"中的 "Windows"。

2.3.4 反向引用:

举例:

1、要匹配两个连续的相同数字:

1.(\\d)\\1

2、要匹配五个连续的相同数字:

1.(\\d)\\1{4}

3、要匹配个位与千位相同,十位与百位相同的数:

1.如 1221、2332:

2.(\\d)(\\d)\\2\\1

4、在字符串中检索商品编号:

1.形式如:12321-333999111,这样的号码:

2.要求满足前面是一个五位数,然后一个 - 号,然后是一个九位数,连续的每三位都要相同

3.\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}

5、结巴去重案例:

1.去掉 . 和重复的字

String content = "我....我要....学学学学学....编程Java";

System.out.println("content=" + content);

// 1、去掉所有的.

Pattern pattern = Pattern.compile("\\.");

Matcher matcher = Pattern.matcher(content);

// 2、去掉重复的字

// 思路:

//(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.o

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