`
kabike
  • 浏览: 608545 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

正则表达式 捕获组,向前引用,零宽度断言,贪婪量词,惰性量词以及支配量词

阅读更多
捕获组
正则表达式中的括号相当于一个分组,比如下面这个正则表达式,就把字符串分成了"_"分割的三个分组,
然后可以利用$1引用第一个分组,$3引用第三个分组
		Pattern p = Pattern.compile("([^_]+)_(\\d+)_([^_]+)");
		String src1 = "孙燕姿_20091103_遇见.mp3";
		Matcher m = p.matcher(src1);
		System.out.println(m.replaceAll("$1_$3"));
		//output 孙燕姿_遇见.mp3


向前引用
假设想匹配字符串中的"hello hello"这样的字串是很容易的,但是想匹配所有的这样的重复字符串呢(比如 "aaa aaa"和"www www")?
可以利用向前引用,即寻找已经匹配的捕获组.
比如下面这个正则表达式,寻找这样的匹配模式:多个字母(形成了捕获组1),一个空格,捕获组1
		Pattern p = Pattern.compile("(\\w+)\\s\\1");
		String src = "I always make make some mistakes when when writting.";
		Matcher m = p.matcher(src);
		while (m.find()) {
			System.out.println(m.group());
		}
		//output make make
		 		 when when


零宽度断言
假设想提取字符串中的括号中的数字(不包括括号),其实可以用这样的模式
(\d+)
但是这样会把括号也包括到匹配结果中,还要最后去掉括号.这时可以考虑零宽度断言,零宽度断言就像一种判断,
比如下面这个正则表达式,匹配的模式为: 多个数字,并且这些数字之前是"(",并且这些数字之后是")"
		Pattern p = Pattern.compile("(?<=\\()\\d+(?=\\))");
		String src = "some useless word (497872028) some other crap 1321112232";
		Matcher m = p.matcher(src);
		while (m.find()) {
			System.out.println(m.group());
		}
		
		// output 497872028

这个可以有如下变体.提取括号以及@@之间的 数字(不包括括号和@@)
		Pattern p = Pattern.compile("(?<=\\(|@@)\\d+(?=\\)|@@)");
		String src = "some @@497872027@@ useless word (497872028) some other crap 1321112232";
		Matcher m = p.matcher(src);
		while (m.find()) {
			System.out.println(m.group());
		}
		
		// output 497872027
		// output 497872028	


贪婪量词和惰性量词
考虑这个例子,提取##之间的部分(包括#),很容易想
		Pattern p = Pattern.compile("#.+#");
		String src = "some #stupid# word and some crap";
		Matcher m = p.matcher(src);
		while (m.find()) {
			System.out.println(m.group());
		}
		// #stupid#

那么字符串改一下呢
		Pattern p = Pattern.compile("#.+#");
		String src = "some #stupid# word and some #crap#";
		Matcher m = p.matcher(src);
		while (m.find()) {
			System.out.println(m.group());
		}
		// #stupid# word and some #crap#

因为默认情况下正则表达式的量词(即那个+)是贪婪的,它尝试尽可能多的匹配.
这时可以试下惰性量词,在+后面加?,表示尽可能少的进行匹配.
		Pattern p = Pattern.compile("#.+?#");
		String src = "some #stupid# word and some #crap#";
		Matcher m = p.matcher(src);
		while (m.find()) {
			System.out.println(m.group());
		}
		// #stupid#
		// #crap#

其实不用惰性量词,用 #[^#]+# 也可以

支配量词
支配量词比较复杂,我也不是完全清楚,这里谈一些个人见解,
我感觉它工作起来像贪婪量词,但是它不回溯,因为支配量词丢弃原来的状态.
比如贪婪量词模式 是\\w+:
字符串是 hello,那么这个字符串是肯定不满足模式的,因为它末尾没有那个分号.
不过贪婪量词先用 \\w+匹配 hello,发现不成功,进行回溯,就是用\\w+匹配hell,依然失败,接着匹配hel.
直到完全失败为止.

支配量词模式为\\w++:
在\\w++匹配了hello之后,发现后面没有分号,匹配失败,要进行回溯.但是支配量词没有保留h he hel hell这几个中间状态,
所以无法回溯,直接失败.
因此支配量词在这种情况下理论上效率会高一些,因为它少了这些回溯中间状态的步骤.
先看贪婪量词
		Pattern p = Pattern.compile("\\w+:");
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i <= 40; i++) {
			sb.append("alonglongsentence");
		}

		String src = sb.toString();
		long start = System.currentTimeMillis();
		for (int i = 0; i <= 100; i++) {
			p.matcher(src).find();
		}

		System.out.println(System.currentTimeMillis() - start);
		//1391

下面用支配量词
		Pattern p = Pattern.compile("\\w++:");
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i <= 40; i++) {
			sb.append("alonglongsentence");
		}

		String src = sb.toString();
		long start = System.currentTimeMillis();
		for (int i = 0; i <= 100; i++) {
			p.matcher(src).find();
		}

		System.out.println(System.currentTimeMillis() - start);
		// 875

上面都是匹配失败的情况,下面试试成功的.因为成功不需要回溯,因此速度快了很多嘛.为了对比,我把字符串长度和匹配次数都变大了.
		Pattern p = Pattern.compile("\\w+:");
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i <= 400; i++) {
			sb.append("alonglongsentence");
		}
		sb.append(":");
		String src = sb.toString();
		long start = System.currentTimeMillis();
		for (int i = 0; i <= 1000; i++) {
			p.matcher(src).find();
		}

		System.out.println(System.currentTimeMillis() - start);
		// 250
		
		Pattern p = Pattern.compile("\\w++:");
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i <= 400; i++) {
			sb.append("alonglongsentence");
		}
		sb.append(":");
		String src = sb.toString();
		long start = System.currentTimeMillis();
		for (int i = 0; i <= 1000; i++) {
			p.matcher(src).find();
		}

		System.out.println(System.currentTimeMillis() - start);
		// 235

现在差别就不明显了.
关于贪婪量词和支配量词
我猜测字符串a12b  和模式a\d+c匹配过程如下
那个逗号表示匹配的位置

,a12b ,a\d+c
a,12b a,\d+c
a1,2b a,\d+c  记录回溯状态 a1,2b a\d+,c
a12,b a,\d+c  记录回溯状态 a12,b a\d+,c
b匹配\d失败,回溯状态为a12,b a\d+,c
b匹配c失败,回溯状态为a1,2b a\d+,c
2匹配c失败,没有状态可以回溯,匹配失败

换成支配量词
a12b  a\d++c

,a12b ,a\d++c
a,12b a,\d++c
a1,2b a,\d++c  记录回溯状态a1,2b a\d++,c
a12,b a,\d++c  记录回溯状态a12,b a\d++,c
b匹配\d失败,回溯状态为a12,b a\d++,c 丢弃其他回溯状态
b匹配c失败,没有状态可以回溯,匹配失败

看出来支配量词回溯步骤变少了.a b之间的数字越多,它比贪婪量词要回溯的就越少

关于捕获组和零宽度断言,后来又补充了一部分内容https://www.jianshu.com/p/31b13caa332c
1
9
分享到:
评论

相关推荐

    正则表达式转换工具

    正则表达式(Regular Expression,简称regex)是一种强大的文本处理工具,它用于匹配、查找、替换等操作,涉及字符串处理的各个领域。正则表达式转换工具是专门针对这一需求而设计的,它能帮助用户将输入的内容转换...

    正则表达式在数据库查询中的应用

    - **分组与引用**:使用圆括号`()`来定义一个捕获组,并可以通过`\1`、`\2`等引用之前捕获的组。 #### 正则表达式在SQL中的应用 在数据库查询中使用正则表达式可以显著提高查询的灵活性和效率。具体应用场景包括但...

    vb正则表达式实例(正则表达式测试程序)

    下面将详细探讨正则表达式的基本概念、在VB.NET中的应用以及如何使用它们进行文本匹配。 1. 正则表达式基础 - **模式匹配**:正则表达式是一种特殊的字符序列,用于定义字符串的搜索模式。 - **元字符**:如 `.`...

    C语言正则表达式库

    1. **语法兼容性**:如描述所述,PCRE库的正则表达式语法与Perl语言高度兼容,这意味着开发者可以利用Perl中广泛使用的正则表达式语法,如贪婪和非贪婪量词、分支选择、反向引用等。 2. **Unicode支持**:PCRE库...

    pb 使用正则表达式源码pbregexp

    5. **捕获组**:提取匹配的子串,特别是对于包含括号的正则表达式,可以获取多个匹配部分。 6. **修饰符**:如全局匹配(g)使匹配不局限于第一个出现的位置,忽略大小写(i)等。 “pbregexp”组件可能提供了相应...

    正则表达式测试工具C#版(src)

    正则表达式是一种强大的文本处理工具,用于在字符串中进行模式匹配和搜索。在C#编程语言中,正则表达式被广泛应用于数据验证、文本提取、格式转换等多个场景。本项目提供了一个C#编写的正则表达式测试工具,包含完整...

    正则表达式(Deelx版)|正则表达式(Deelx版)支持库

    正则表达式(Deelx版)是一种强大的文本处理工具,它允许程序员和用户通过预定义的模式来匹配、查找、替换或者分析字符串。Deelx版是专门为提高正则表达式性能和功能而设计的一个支持库,适用于各种编程语言和应用场景...

    正则表达式调试工具

    正则表达式(Regular Expression,简称regex)是用于在文本中匹配特定模式的强大工具,广泛应用于数据验证、搜索替换和文本处理等领域。正则表达式调试工具是开发人员用来测试和优化这些模式的重要辅助工具。本文将...

    java正则表达式.zip

    Java正则表达式是Java编程语言中用于处理字符串的强大工具,它基于模式匹配的概念,能够高效地进行文本搜索、替换和解析。在Java中,正则表达式主要通过`java.util.regex`包来实现,提供了Pattern和Matcher两个核心...

    正则表达式生成工具,正则表达式生成工具

    正则表达式(Regular Expression,简称regex)是一种用于匹配字符串的强大工具,广泛应用于文本处理、数据验证、搜索和替换等场景。在编程语言中,正则表达式通常以字符串的形式存在,通过特定的语法和模式来定义...

    强大的正则表达式生成工具 C#版

    正则表达式是一种强大的文本处理工具,用于在字符串中进行模式匹配和搜索替换操作。C#作为.NET框架的一部分,提供了全面支持正则表达式的类库,使得开发人员能够方便地利用正则表达式进行复杂的文本处理任务。在这个...

    易语言正则表达式文本替换

    例如,"子程序_正则文本替换"可能就是一个易语言中用于执行正则表达式替换的子程序,它接收输入的文本、正则表达式模式和替换字符串,然后返回经过替换操作的新文本。 1. **正则表达式基础** - **元字符**:如`.`...

    正则表达式学习资料以及练习项目代码很多

    正则表达式(Regular Expression,简称regex)是用于匹配字符串的一种模式,广泛应用于文本处理、数据验证、搜索和替换等场景。在Python编程语言中,正则表达式提供了强大的文本处理能力,使得开发者能够高效地处理...

    正则表达式速查 正则表达式举例 正则表达式学习

    ### 正则表达式基础知识与应用详解 #### 一、正则表达式简介 正则表达式(Regular Expression)是一种强大的文本处理工具,能够帮助我们完成对字符串的搜索、替换等操作。它广泛应用于各种编程语言中,如JavaScript...

    qt正则表达式测试工具

    - 利用工具提供的功能,如捕获组、模式修饰符等,优化正则表达式。 - 检查正则表达式的性能,避免过度复杂的模式导致效率降低。 在实际开发中,熟练掌握Qt的QRegExp类和正则表达式语法,能大大提高处理文本数据的...

    java正则表达式匹配工具

    Java正则表达式匹配工具是IT领域中一种强大的文本处理工具,它利用正则表达式(Regular Expression)的规则来查找、替换或者提取文本中的特定模式。正则表达式是一种特殊的字符序列,能够帮助程序员或者用户高效地...

    JAVA正则表达式大全

    ...)`,或者后向引用`\number`,以及非捕获组 `(?:...)`。 5. **JAVA正则表达式--Pattern和Matcher.doc** 这份文档可能深入讲解了`Pattern`和`Matcher`类的用法,如`Pattern.compile()`用于编译正则表达式,`...

    精通正则表达式(第三版)简体中文版

    本书《精通正则表达式(第三版)简体中文版》主要介绍了正则表达式的概念、语法以及如何在不同的环境中高效地使用正则表达式。 #### 二、正则表达式的语法基础 1. **元字符**:正则表达式中的特殊字符,用于指定...

    正则表达式翻译工具,RegexTest.exe

    正则表达式(Regular Expression,简称regex)是一种强大的文本处理工具,用于匹配、查找、替换或提取特定模式的字符串。RegexTest.exe 是一个专门用于测试和解析正则表达式的应用程序,它可以帮助用户理解和调试...

    精通正则表达式中文版英文版_中文版为扫描版

    在正则表达式的世界里,基础概念包括字符类(如匹配任何数字[\d])、量词(匹配0次或多次*,1次或多次+,至少n次{n}等)、分组与捕获(使用括号()来定义一个子模式)、预查(用^符号否定预查,如[^abc]匹配非abc的...

Global site tag (gtag.js) - Google Analytics