【后端】正则表达式&java正则学习笔记

文章目录

  • 1.概念
  • 2.基础语法
    • 2.1 正则表达式是什么?
    • 2.2 导入的包
    • 2.3 基本用法
      • 2.3.1 元字符(包含除了 普通字符外的所有字符:限定符,连接符等等)
      • 2.3.2 连接符
      • 2.3.3 限定符
      • 2.3.4 定位符
      • 2.3.5 转义字符
      • 2.3.6 分组或捕获
      • 2.3.7 反向引用
      • 2.3.8 选择符
      • 2.3.9 优先级顺序

参考地址: 正则表达式(总结篇)
正则表达式教程

1.概念

正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。在众多语言中都可以支持正则表达式,如Perl、PHP、Java、Python、Ruby等。当然在Java中也可以通过处理字符串的方式达到检索,替换文本字符串的目的,但是有了正则表达式写代码更加简洁,通常两三行代码就可以达到目的,当然这也是建立在熟悉正则表达式的基础之上的。

2.基础语法

2.1 正则表达式是什么?

正则表达式,就是用某种模式去匹配一类字符串的公式。学习正则表达式就是学习怎样定义一种“模式”的语法,说白了,就是学习各种匹配的规则,例如匹配数字要怎么写,匹配字符要怎么写等等。

2.2 导入的包

在java中调用正则表达式的类是java.util.regex.Matcher和java.util.regex.Pattern,java.util.regex包是从jdk1.4开始提供的。有多种写法来使用正则表达式。

2.3 基本用法

2.3.1 元字符(包含除了 普通字符外的所有字符:限定符,连接符等等)

  • \ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,‘n’ 匹配字符 “n”。‘\n’ 匹配一个换行符。序列 ‘\’ 匹配 “” 而 “(” 则匹配 “(”。
  • . 匹配除换行符(\n、\r)之外的任何单个字符。要匹配包括 ‘\n’ 在内的任何字符,请使用像"(.|\n)"的模式。
  • (pattern) 匹配 pattern 并获取这一匹配。
  • (?:pattern) 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 “或” 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 ‘industry|industries’ 更简略的表达式。
  • (?=pattern) 正向肯定预查(look ahead positive assert),在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)“能匹配"Windows2000"中的"Windows”,但不能匹配"Windows3.1"中的"Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
    (?!pattern) 正向否定预查(negative assert),在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如"Windows(?!95|98|NT|2000)“能匹配"Windows3.1"中的"Windows”,但不能匹配"Windows2000"中的"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
    (?<=pattern) 反向(look behind)肯定预查,与正向肯定预查类似,只是方向相反。例如,“(?<=95|98|NT|2000)Windows"能匹配"2000Windows"中的"Windows”,但不能匹配"3.1Windows"中的"Windows"。
    (?
  • x|y 匹配 x 或 y。例如,‘z|food’ 能匹配 “z” 或 “food”。‘(z|f)ood’ 则匹配 “zood” 或 “food”。
  • [xyz] 字符集合。匹配所包含的任意一个字符。例如, ‘[abc]’ 可以匹配 “plain” 中的 ‘a’。
  • [^xyz] 负值字符集合。匹配未包含的任意字符。例如, ‘[^abc]’ 可以匹配 “plain” 中的’p’、‘l’、‘i’、‘n’。
  • [a-z] 字符范围。匹配指定范围内的任意字符。例如,‘[a-z]’ 可以匹配 ‘a’ 到 ‘z’ 范围内的任意小写字母字符。
  • [^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。例如,‘[^a-z]’ 可以匹配任何不在 ‘a’ 到 ‘z’ 范围内的任意字符。
  • \cx 匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 ‘c’ 字符。
  • \d 匹配一个数字字符。等价于 [0-9]。
  • \D 匹配一个非数字字符。等价于 [^0-9]。
  • \w 匹配字母、数字、下划线。等价于[A-Za-z0-9_]
  • \W 匹配非字母、数字、下划线。等价于 [^A-Za-z0-9_]
  • \s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
  • \S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]
  • \f 匹配一个换页符。等价于 \x0c 和 \cL。
  • \n 匹配一个换行符。等价于 \x0a 和 \cJ。
  • \r 匹配一个回车符。等价于 \x0d 和 \cM。
  • \t 匹配一个制表符。等价于 \x09 和 \cI。
  • \v 匹配一个垂直制表符。等价于 \x0b 和 \cK。
  • \xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,‘\x41’ 匹配 “A”。‘\x041’ 则等价于 ‘\x04’ & “1”。正则表达式中可以使用 ASCII 编码。
  • \num 匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,‘(.)\1’ 匹配两个连续的相同字符。
  • \n 标识一个八进制转义值或一个向后引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为向后引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。
  • \nm 标识一个八进制转义值或一个向后引用。如果 \nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。
  • \nml 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。
  • \un 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。

2.3.2 连接符

在正则表达式中,匹配数字或者英文字母的书写非常不方便。因此,正则表达式引入了连接符“-”来定义字符的范围。

  • [0-9] 匹配数字,等价于\d
  • [a-z] 匹配英文小写字母
  • [A-Z] 匹配英文大写字母
  • [0-9a-zA-Z] 匹配大小写英文,数字。

当连接符 - 出现在方括号 [ ] 内的首位或末位时,它不会被解释为范围,而是作为普通字符进行匹配。如:[\w.-]

2.3.3 限定符

限定符,就是限定某个或某类字符出现的次数。

  • * 匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等价于{0,}。
  • + 匹配前面的子表达式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。
  • ? 匹配前面的子表达式零次或一次。例如,“do(es)?” 可以匹配 “do” 或 “does” 。? 等价于 {0,1}。
  • {n} n 是一个非负整数。匹配确定的 n 次。例如,‘o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。
  • {n,} n 是一个非负整数。至少匹配n 次。例如,‘o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。‘o{1,}’ 等价于 ‘o+’。‘o{0,}’ 则等价于 ‘o*’。
  • {n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,“o{1,3}” 将匹配 “fooooood” 中的前三个 o。‘o{0,1}’ 等价于 ‘o?’。请注意在逗号和两个数之间不能有空格。
  • ? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 “oooo”,‘o+?’ 将匹配单个 “o”,而 ‘o+’ 将匹配所有 ‘o’。

2.3.4 定位符

在正则表达式中,定位符,说白了,就是限定某些字符出现的位置。
常用的正则表达式定位符如下:

  • ^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 ‘\n’ 或 ‘\r’ 之后的位置。
  • $ 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 ‘\n’ 或 ‘\r’ 之前的位置。
  • \b 匹配一个单词边界,也就是指单词和空格间的位置。例如, ‘er\b’ 可以匹配"never" 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。【 \b 是用来匹配单词边界的。它放在字符前表示匹配单词结尾的位置,放在字符后表示匹配单词开头的位置。】
  • \B 匹配非单词边界。‘er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。

2.3.5 转义字符

需要转义的字符有:$、( 、) 、* 、+ 、. 、[ 、] 、? 、\ 、/ 、^、{ 、} 、| 。
在该特殊字符前面加上反斜杠“\”将其进行转义

2.3.6 分组或捕获

  • () 分组又称为子表达式,即把一个正则表达式的全部或部分分成一个或多个组。其中,分组使用的字符为“(”和“)”,即左圆括号和右圆括号。分组之后,用小括号括起来的表达式看出一个整体来处理。
  • (?: ) 用于分组但不捕获子表达式,用于分组模式而不创建捕获组,不影响匹配结果,消耗字符,下一字符匹配会从已匹配后的位置开始
  • (?=) 正向先行断言 在当前位置的右侧,要求字符串后面的部分匹配 pattern。不会消耗字符,只是做条件检查
  • (?!) 负向先行断言 在当前位置的右侧,要求字符串后面的部分不匹配 pattern。同样不会消耗字符,只是做条件检查
  • (?<=)正向后行断言 在当前位置的左侧,要求字符串前面的部分匹配 pattern。同样不会消耗字符,只是做条件检查
  • (?在当前位置的左侧,要求字符串前面的部分不匹配 pattern。也不会消耗字符,只是做条件检查
(?:)” 是用来创建非捕获分组的语法结构。在正则表达式中,通常会使用圆括号来创建捕获分组,用于将匹配的结果捕获到一个分组中,以便后续引用或获取。但是有时候,我们只需要分组来进行逻辑分组或设置子模式的优先级,而不需要捕获该分组的结果。这时,就可以使用非捕获分组。
例如,正则表达式"(?:ab)+"会匹配连续出现的"ab"字符串,但只对整个匹配结果进行捕获,其中每个"ab"子字符串并不会被单独捕获。
 public void patternTest3() {
        String input = "I have 2 cats and 3 dogs";
        String regex = "(\\d+) (\\w+)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        while (matcher.find()) {
            String number0 = matcher.group(0);  // 代表整个匹配到的字符串。即匹配结果的第 0 个分组,通常是整个正则表达式匹配的字符串。
            String number = matcher.group(1);  // 第一个圆括号内的表达式捕获的数字
            String animal = matcher.group(2);  // 第二个圆括号内的表达式捕获的动物类型
            System.out.println(number0);
            System.out.println("Number: " + number + ", Animal: " + animal);
            /**
             * 循环输出
             * 2 cats
             * Number: 2, Animal: cats
             * 3 dogs
             * Number: 3, Animal: dogs
             */
        }
    }
  public void patternTest33() {
        String input = "I have 2 cats and 3 dogs";
        String regex = "(?:\\d+) (\\w+)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        while (matcher.find()) {
            String number0 = matcher.group(0);  // 代表整个匹配到的字符串。即匹配结果的第 0 个分组,通常是整个正则表达式匹配的字符串。
            String animal = matcher.group(1);  // 第二个圆括号内的表达式捕获的数字
            System.out.println(number0);// 2 cats   3 dogs
            System.out.println("Animal: " + animal);//循环输出cats, dogs;
            /**
             * 循环输出
             * 2 cats
             * Animal: cats
             * 3 dogs
             * Animal: dogs
             */
        }
    }

 //分组但不捕获,正向预查
    @Test
    public void patternTest333() {
        String input = "123456run123run456";
        String regex = "run(?=[\\d])";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        while (matcher.find()) {
            String number0 = matcher.group(0);  // 代表整个匹配到的字符串。即匹配结果的第 0 个分组,通常是整个正则表达式匹配的字符串。
            System.out.println(number0);
            /**
             * 循环输出
             * run
             * run
             */
        }
    }
  //分组但不捕获,负向预查
    @Test
    public void patternTest3333() {
        String input = "123456runa123run456";
        String regex = "run(?![\\d])";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        while (matcher.find()) {
            String number0 = matcher.group(0);  // 代表整个匹配到的字符串。即匹配结果的第 0 个分组,通常是整个正则表达式匹配的字符串。
            System.out.println(number0);
            /**
             * 循环输出
             * run
             */
        }
    }
import re
 
# (?=pattern) 简单说,以 xxx(?=pattern)为例,就是捕获以pattern结尾的内容xxx
 
 
print(re.findall("Windows(?=95|98|NT|2000)", "Windows2000_WindowsNT_WindowsXP")) # ['Windows', 'Windows']
 
 
# (?!pattern) 简单说,以 xxx(?!pattern)为例,就是捕获不以pattern结尾的内容xxx
 
print(re.findall("Windows(?!95|98|NT|2000)", "Windows2000_WindowsNT_WindowsXP")) # ['Windows']
 
 
# (?<=pattern) 简单说,以(?<=pattern)xxx为例,就是捕获以pattern开头的内容xxx
 
print(re.findall("(?<=2000)year", "abc2000year444")) #  ['year']
 
# (?<!pattern) 简单说,以(?<!pattern)xxx为例,就是捕获不以pattern开头的内容xxx。
 
print(re.findall("(?, "032year444")) #  ['year']
 
 

2.3.7 反向引用

使用在正则表达式模式中通过捕获组(用括号 () 包裹的部分)所捕获的内容
在正则表达式中,反向引用的语法是使用\加上捕获组的编号(或者捕获组的名称)。捕获组的编号从左到右从 1 开始,依次递增。
[反向引用通常与捕获组结合使用]

//反向引用
    @Test
    public void patternTest3333333() {
        String input = "123456run123run456";
        String regex = "(run)[\\d]+\\1";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        while (matcher.find()) {
            String number0 = matcher.group(0);  // 代表整个匹配到的字符串。即匹配结果的第 0 个分组,通常是整个正则表达式匹配的字符串。
            System.out.println(number0);
            /**
             * 循环输出
             * run123run
             */
        }
    }

2.3.8 选择符

选择匹配符,很简单。在正则表达式中,选择匹配符是“|”,用于选择匹配2个选项之中的任意一个,类似JavaScript中的“或”运算。
例如,“abc|def1”匹配的是“abc”或“def1”,而不是“abc1”或“def1”。如果要匹配“abc1”或“def1”,应该使用分组符,即“(abcd|efgh)1”。

2.3.9 优先级顺序

运算符或表达式 说明
‘\’ 转义符
()、(?:)、(?=)、[] 圆括号或方括号
*、+、?、{n}、{n,}、{n,m} 限定符
‘|’ 选择符,“或"运算

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