正则表达式进阶 (java)

2023年 7月 15日 60.6k 0

前言

本文所讲的是正则进阶知识,不对正则基础知识过多描述,代码采用java语言编写。

一个完整的正则表达式由两种字符构成:特殊字符(元字符)和普通字符,特殊字符是我们学习正则表达式中的通配符。

正则匹配三种模式

贪婪模式

在java中,模式默认为贪婪模式。
贪婪模式会尽可能多地匹配符合规则的字符。当采用贪婪模式时,正则表达式引擎将向前查找并匹配尽可能多的字符,直到找不到符合条件的字符为止。贪婪模式下的重复匹配操作符主要包括:

  • *:匹配前一个字符或组零次或更多次。
  • +:匹配前一个字符或组一次或更多次。
  • {m,n}:匹配前一个字符或组最少 m 次,最多 n 次。

例如,对于字符串 "aabbcc" 和正则表达式 ab*c,贪婪模式下,匹配结果为 "aabb"(匹配了两个 b),代码块如下:

import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GroupExample {
    public static void main(String[] args) {
        Pattern pattern = Pattern.compile("ab.*c");
        Matcher matcher = pattern.matcher("aabbcc");
        if (matcher.find())
        {
            System.out.println(matcher.group());
        }
    }
}

输出将是:

abbcc

懒惰模式 (非贪婪模式)

在正则表达式语法中,问号(“?”)具有两种不同的含义,取决于它在正则表达式的什么位置。
当问号跟在重复限定符(如星号“”或加号“+”)的后面时,它会将匹配模式变为非贪婪,从而实现懒惰匹配。这意味着正则表达式引擎会尝试尽可能少的匹配字符,直到找到满足模式的最短字符串。
例如,正则表达式“a.?b”中的问号就是在星号后面使用的,它将星号的贪婪匹配模式变为非贪婪模式,从而实现了懒惰匹配。
另一方面,当问号不跟在重复限定符的后面时,它表示可选项,可以将前面的字符或组指定为可选的。这个问号通常称为零宽度断言(lookaround),因为它不匹配任何字符,而只是断言某些条件满足。

因此,问号在正则表达式中的含义取决于它的上下文和使用方式。加上问号可以实现懒惰匹配,但它也可以用于其他不同的目的。
举一个例子,对于字符串 "aabbcc" 和正则表达式 ab*c,懒惰模式下,匹配结果为 "aabb"(匹配了两个 b),代码块如下:

import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GroupExample {
    public static void main(String[] args) {
        Pattern pattern = Pattern.compile("ab.*?c");
        Matcher matcher = pattern.matcher("aabbcc");
        if (matcher.find())
        {
            System.out.println(matcher.group());
        }
    }
}

输出将是:

abbc

所以二者的区别在于:

贪婪模式:找出长度最大并且符合要求,尽可能多地去匹配。

懒惰模式:找出长度最小且符合要求的。

独占模式

*+:占有性限定符。它将匹配前一个字符或组零次或多次,但在匹配过程中,它不会回溯。
对于字符串 "aaab" 和正则表达式 a*+,匹配到了3个 'a'。尽管占有性限定符不会回溯,但在这种情况下,结果与贪婪限定符相同。

总结

在正则表达式的三种模式(贪婪、非贪婪和占有性)中,贪婪模式和非贪婪模式会进行回溯(backtracking),而占有性模式不会回溯。

  • 贪婪模式:它首先尝试最大化匹配。如果在后续的正则表达式部分发生不匹配,它会回溯,尝试较少的字符匹配。
  • 非贪婪模式:它开始时尝试最小化匹配。如果后续的正则表达式部分需要更多字符来满足匹配条件,则会逐步回溯,增加所匹配的字符数量。
  • 占有性模式:它试图最大化匹配,但匹配一旦完成,将不会释放(回溯)已匹配的字符。这意味着,占有性模式会保留当前匹配,并不会尝试其他匹配选项。
  • 在实际使用中,选择合适的模式取决于您的需求和预期匹配结果。回溯可能会影响正则表达式性能,而占有性模式可以在某些情况下避免性能问题。然而,请注意,占有性模式可能使得正则表达式无法找到有效匹配。

    group 函数的作用

    在 Java 中,正则表达式通常与 Pattern 和 Matcher 类一起使用。
    其中,Matcher 类提供了一个名为 group 的函数,用来获取匹配到的子串或者某个分组(group)的内容。
    在正则表达式中,可以使用括号将一部分表达式括起来,从而创建一个分组。例如,正则表达式 (ab)+ 匹配一个或多个由字符串 "ab" 组成的组合,其中括号中的 + 表示一个或多个,而加号前面的括号表示一个分组。
    当使用 Matcher 类的 find() 方法或 matches() 方法进行正则表达式匹配时,如果匹配成功,可以使用 group() 方法获取匹配到的整个子串,或者使用 group(int groupNum) 方法获取某个特定分组的内容。
    例如,以下代码演示了如何使用 Matcher 类的 group() 方法获取匹配到的子串和分组内容:

    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    public class GroupExample {
       public static void main(String[] args) {
          String input = "ababab";
          String patternString = "(ab)+";
          Pattern pattern = Pattern.compile(patternString);
          Matcher matcher = pattern.matcher(input);
    
          if (matcher.find()) {
             System.out.println("Matched string: " + matcher.group());
             System.out.println("Group 1: " + matcher.group(1));
          }
       }
    }
    

    输出将是:

    Matched string: ababab
    Group 1: ab
    

    环视(Lookaround)

    环视分为四种,分别是顺序肯定环视,顺序否定环视,逆序肯定环视,逆序否定环视。

    顺序环视 表达式
    顺序否定环视 (?!expression)
    顺序肯定环视 (?=expression)
    逆序否定环视 (?
    逆序肯定环视 (?

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论