正则表达式中的 ?

在正则表达式中,?既可以表示数量,0次或1次,等效于 {0,1},也可以作为特殊字符,表示其它含义。

非贪心匹配

? 跟在其它数量限定符之后,表示非贪心匹配,即匹配时匹配搜索到的尽可能短的字符串。

下面来看一个例子:

@Test
public void test() {
	Pattern pattern = Pattern.compile("a.*?");
	Matcher matcher = pattern.matcher("abcabc");
	if (matcher.matches()) {
		System.out.println(matcher.group());
	}
}

执行后输出:abcabc

不是最短匹配吗?为什么失灵了?

这其实牵涉到非贪心匹配的规则:非贪心匹配,到下一个规则前,匹配最短路径,如果没有下一个规则,按贪心匹配处理。

也就是说如果只出现 "a.*?" 还是按贪心匹配处理。

下面来看正确的使用:

@Test
public void test() {
	Pattern pattern = Pattern.compile("(a.*?)(.*)");
	Matcher matcher = pattern.matcher("afcafc");
	if (matcher.matches()) {
		System.out.println(matcher.group(0));
		System.out.println(matcher.group(1));
		System.out.println(matcher.group(2));
	}
}

执行后输出:

afcafc
a
fcafc

可以看到,第一个捕获组捕获到了最短的字符串 "a",第二个捕获组捕获到了 "fcafc"。

下面再来看看另外两种情况:

  • "(a.*)(.*)"  第一个捕获组会捕获所有,第二个不会报错,但什么也捕获不到
  • "(a.*?)(.*?)"  第一个捕获组会捕获 "a",第二个捕获组会捕获 "fcafc",因为后面没有其它规则了,按贪心匹配处理。

匹配但不捕获 (?:pattern) 

用在捕获组中,?: 放在正则表达式之前,表示匹配但不捕获,即通过 group 方法获取不到这一组匹配的值。

下面来看示例

@Test
public void test0() {
	Pattern pattern = Pattern.compile("\\d{4}-(?:[a-z]+)");
	Matcher matcher = pattern.matcher("3214-opo");
	if (matcher.matches()) {
		System.out.println(matcher.group());
		System.out.println(matcher.group(1)); // 报错
	}
}

通过 group(1) 进行捕获时会报错,即可以匹配,但不能捕获。若将 ?: 去掉,则通过 group(1) 可正常捕获。

开启单行模式 (?s)

(?s) 右侧开启单行模式,使 . 与任意字符匹配,包括换行符 \n。

下面来看示例:

private static final String DEFAULT_VARIABLE_PATTERN = "((?s).*)";


/**
 * 从输出结果可知,匹配到了换行符 '\n'
 */
@Test
public void test4() {
	Pattern pattern = Pattern.compile(DEFAULT_VARIABLE_PATTERN);
	Matcher matcher = pattern.matcher("abc\nsdf");
	if (matcher.matches()) {
		System.out.println(matcher.group());
		System.out.println(matcher.group(1));
		System.out.println(matcher.group(2)); // (?s) 不能作为捕获组,报错
	}
}

捕获时 (?s) 并不能作为捕获组来捕获,所以 "((?s).*)" 最大捕获到 group(1),捕获 group(2) 时报错。

@Test
public void test5() {
	Pattern pattern = Pattern.compile("(.*)");
	Matcher matcher = pattern.matcher("abc\nsdf");
	if (matcher.matches()) {
		System.out.println(matcher.group());
		System.out.println(matcher.group(1));
	}
}

去掉 (?s) 之后,再去匹配 "abc\nsdf",因为存在换行符,并不能匹配完成,所以什么也不会输出。
 

相关推荐

  1. 表达式 ?

    2024-07-12 21:44:02       20 阅读
  2. shell表达式---RE

    2024-07-12 21:44:02       54 阅读
  3. 精通Python表达式

    2024-07-12 21:44:02       50 阅读
  4. 精通Python表达式

    2024-07-12 21:44:02       53 阅读
  5. 表达式元字符使用

    2024-07-12 21:44:02       36 阅读
  6. python表达式

    2024-07-12 21:44:02       25 阅读
  7. python表达式

    2024-07-12 21:44:02       18 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-12 21:44:02       49 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-12 21:44:02       53 阅读
  3. 在Django里面运行非项目文件

    2024-07-12 21:44:02       42 阅读
  4. Python语言-面向对象

    2024-07-12 21:44:02       53 阅读

热门阅读

  1. 图数据库 - Neo4j详解

    2024-07-12 21:44:02       16 阅读
  2. 二叉树专题刷题

    2024-07-12 21:44:02       19 阅读
  3. 【Leetcode 每日一题】349. 两个数组的交集

    2024-07-12 21:44:02       19 阅读
  4. 力扣题解(环绕字符串中唯一的子字符串)

    2024-07-12 21:44:02       13 阅读
  5. python连接kafka生产者发送消息

    2024-07-12 21:44:02       16 阅读
  6. 链路追踪详解(六):Zipkin 和 Jaeger 的安装方法

    2024-07-12 21:44:02       14 阅读
  7. 进制-奇怪的捐赠c++

    2024-07-12 21:44:02       15 阅读
  8. flutter 使用wechat_assets_picker的权限检测

    2024-07-12 21:44:02       13 阅读
  9. Sqlmap中文使用手册 - Request模块参数使用

    2024-07-12 21:44:02       11 阅读
  10. pdf文件如何快速英文转中文?

    2024-07-12 21:44:02       15 阅读
  11. Windows图形界面(GUI)-SDK-C/C++ - 编辑框(edit)

    2024-07-12 21:44:02       19 阅读