今天在项目中遇到这样一个需求:
要求把一段HTML代码中的注释里的某类表达式替换掉,而在注释外的这类表达式不需要替换,例如:
%(/images/a.jpg)
<!-- <image src="%(/images/a.jpg)"> -->
%(/images/a.jpg)
<!-- <image src="%(/images/b.jpg)"> <image src="%(/images/c.jpg)"> -->
%(/images/a.jpg)
其中,在注释内的%(/images/a.jpg)要替换成${contextPath}/images/a.jpg
替换后应该是这样的:
%(/images/a.jpg)
<!-- <image src="${contextPath}/images/a.jpg"> -->
%(/images/a.jpg)
<!-- <image src="${contextPath}/images/b.jpg"> <image src="${contextPath}/images/c.jpg"> -->
%(/images/a.jpg)
经过一番研究,深入了解了一下greedy、reluctant和possessive这些量词的区别(可以参考一下),以及Special constructs (non-capturing)的作用(以前也没对REGEX去太多研究,只用点简单的),留下代码,以供日后查阅
/**
* Replace special symbol in html comments, like "<!-- %(/images/a.jpg) -->"
* @param text
* @return
*/
protected String replaceSpecialSymbolInComments(String text) {
log.debug("call replaceSpecialSymbolInComments(" + text + ")");
if (text == null) return text;
String commentRegex = "(?s)(?<=<!--).*?(?=-->)";
String specialRegex01 = "\\%\\((.*?)\\)";
Pattern commentPattern = Pattern.compile(commentRegex);
Pattern specialPattern01 = Pattern.compile(specialRegex01);
Matcher commentMatcher = commentPattern.matcher(text);
StringBuilder sb = new StringBuilder(text);
int offset = 0;
while (commentMatcher.find()) {
log.debug("comment match result: " + commentMatcher.group());
int commentMatchStart = offset + commentMatcher.start();
int commentMatchEnd = offset + commentMatcher.end();
log.debug(commentMatchStart + " -- " + commentMatchEnd);
Matcher specialMatcher01 = specialPattern01.matcher(commentMatcher.group());
while (specialMatcher01.find()) {
commentMatchStart = offset + commentMatcher.start();
commentMatchEnd = offset + commentMatcher.end();
log.debug("special match result01: " + specialMatcher01.group());
log.debug("special match result01 should be: " + "${contextPath}" + specialMatcher01.group(1));
int specialMatchStart01 = specialMatcher01.start();
int specialMatchEnd01 = specialMatcher01.end();
offset += ("${contextPath}" + specialMatcher01.group(1)).length() - specialMatcher01.group(0).length();
sb.replace(commentMatchStart + specialMatchStart01, commentMatchStart + specialMatchEnd01, "");
sb.insert(commentMatchStart + specialMatchStart01, "${contextPath}" + specialMatcher01.group(1));
}
log.debug("temp result: " + sb.toString());
}
return sb.toString();
}
附录参考:引用 http://zzg810314.iteye.com/blog/194643
greedy、reluctant和possessive量词的区别
greedy、reluctant和possessive量词之间有微妙的区别。
greedy量词被看作“贪婪的”,因为它们在试图搜索第一个匹配之前读完(或者说吃掉)整个输入字符串。如果第一个匹配尝试(整个输入字符串)失败,匹配器就会在输入字符串中后退一个字符并且再次尝试,重复这个过程,直到找到匹配或者没有更多剩下的字符可以后退为止。根据表达式中使用的量词,它最后试图匹配的内容是1 个或者0个字符。
但是,reluctant量词采取相反的方式:它们从输入字符串的开头开始,然后逐步地一次读取一个字符搜索匹配。它们最后试图匹配的内容是整个输入字符串。
最后,possessive量词总是读完整个输入字符串,尝试一次(而且只有一次)匹配。和greedy量词不同,possessive从不后退,即使这样做能允许整体匹配成功。
为了演示,我们分析输入字符串xfooxxxxxxfoo:
Enter your regex: .*foo // greedy quantifier
Enter input string to search: xfooxxxxxxfoo
I found the text "xfooxxxxxxfoo" starting at index 0 and ending at index 13.
Enter your regex: .*?foo // reluctant quantifier
Enter input string to search: xfooxxxxxxfoo
I found the text "xfoo" starting at index 0 and ending at index 4.
I found the text "xxxxxxfoo" starting at index 4 and ending at index 13.
Enter your regex: .*+foo // possessive quantifier
Enter input string to search: xfooxxxxxxfoo
No match found.
第一个例子使用greedy量词.*搜索“任何内容”零次或者多次,后面是字母f、o、o。因为是greedy量词,所以表达式的.*部分首先读完整个字符串。这样,整个表达式不会成功,因为最后三个字母(“f”“o”“o”)已经被消耗了。所以匹配器缓慢地一次后退一个字母,一直后退到最右侧出现“foo”为止,这里匹配成功并且搜索停止。
但是第二个例子使用的量词是reluctant量词,所以它首先消耗“无内容”。因为“foo”没有出现在字符串的开头,所以迫使它消耗掉第一个字母(x),这样就在索引0和4的位置触发第一个匹配。我们的测试示例继续处理,直到输入字符串耗尽为止。它在索引4和13找到了另一个匹配。
第三个例子找不到匹配,因为是possessive量词。这种情况下,.*+消耗整个输入字符串,在表达式的结尾没有剩下满足“foo”的内容。possessive量词用于处理所有内容,但是从不后退的情况;在没有立即发现匹配的情况下,它的性能优于功能相同的greedy量词。
分享到:
相关推荐
正则表达式是一种强大的文本...通过深入研究这个C#版的正则表达式测试工具源码,开发者不仅可以巩固正则表达式的基础知识,还可以提升在C#环境中应用正则表达式的能力,同时学习到UI设计和事件处理等方面的实践技巧。
在Python编程语言中,正则表达式提供了强大的文本处理能力,使得开发者能够高效地处理字符串。这个压缩包包含了丰富的正则表达式学习资源,适合有一定基础的初学者深入学习。 1. **基础概念** - **模式匹配**:...
正则表达式的学习需要对元字符、量词、预查、后向引用等概念有深入理解,同时掌握Java中`Pattern`和`Matcher`的使用方法,结合实际案例进行实践,才能灵活运用到实际项目中。在处理字符串相关问题时,熟练掌握正则...
在正则表达式的世界里,基础概念包括字符类(如匹配任何数字[\d])、量词(匹配0次或多次*,1次或多次+,至少n次{n}等)、分组与捕获(使用括号()来定义一个子模式)、预查(用^符号否定预查,如[^abc]匹配非abc的...
正则表达式由基本字符、元字符和操作符组成,如"."代表任意字符,"*"表示前一个字符可以出现零次或多次。它们可以组合成复杂的模式,用于匹配各种字符串。 DFA(确定有限状态自动机)是一种状态机,有若干个状态和...
【结论】和【资源】部分鼓励开发者通过学习和实践加深对正则表达式的理解,以提升其在开发过程中的应用能力。 总之,掌握正则表达式是每个.NET开发者必备的技能之一,尤其在ASP.NET环境下,正则表达式能够大大提高...
在易语言这个中国本土化的编程环境中,正则表达式被广泛应用于数据验证、文本处理和搜索功能。下面我们将深入探讨易语言中的正则表达式及其应用。 易语言提供了丰富的正则表达式函数库,使程序员能够轻松地实现复杂...
在压缩包的"htmlFiles"中,可能包含了一些关于这些主题的教程、示例代码或文档,帮助学习者深入了解SQL语法分析和正则表达式在实际项目中的应用。这些资源可能涵盖具体的SQL查询语法、正则表达式的模式构造、C#代码...
这里的正则表达式`^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$`涵盖了电子邮件的基本结构,`^`表示开始,`$`表示结束,`\\w`代表字母、数字或下划线,`.`表示点号,`+`表示前面的字符可以出现一次或多次,`*`表示前面的...
10. **最佳实践**:总结在实际项目中使用正则表达式进行表单验证的最佳实践和常见陷阱。 通过学习《C#表单正则表达式验证手册》,开发者能够熟练地运用正则表达式进行复杂的数据验证,提升应用的质量和用户体验。这...
在实践中,书中会讨论如何在各种编程语言中使用正则表达式,如JavaScript、Python、Java等,并给出具体的示例代码,帮助读者理解如何在实际开发中应用正则表达式。此外,书中还会讲解正则表达式引擎的工作原理,这...
`, `{}`, `[]`, `\` 等,它们在正则表达式中有特殊含义。 - **量词**:`*`, `+`, `?`, `{n}`, `{n,}` 和 `{n,m}` 分别表示零个或多个、一个或多个、零个或一个、精确n次、至少n次以及n到m次的匹配。 2. **字符类**...
正则表达式是一种强大的文本模式匹配工具,广泛应用于编程语言如Java中,用于处理字符串数据,实现字符串的搜索、替换、提取等操作。它能够精确描述复杂的文本规则,帮助开发者高效地处理文本数据。 #### 二、入门...
正则表达式是一种强大的文本处理工具,用于匹配、查找、替换和分析字符串模式。...通过阅读"正则表达式.chm"这个文档,相信你能够系统地学习到正则表达式的核心知识,并将其灵活应用到实际项目中。
### 三、Java正则表达式实践 虽然当前版本的JDK还没有内置完整的正则表达式支持,但我们可以使用Jakarta-ORO库来实现。Jakarta-ORO是一个开源项目,提供了强大的正则表达式处理能力。 #### 3.1 使用Jakarta-ORO库 ...
在C++编程环境中,虽然标准库并没有内置正则表达式支持,但通过Microsoft Visual C++(VC++)环境,我们可以利用其提供的库来实现正则表达式的功能。"VC++正则表达式测试工具"正是这样一个实用的小程序,它可以帮助...
3. **正则表达式语法**:学习正则表达式的语法至关重要,例如`^`表示字符串开始,`$`表示字符串结束,`.`匹配任何单个字符,`\d`代表数字,`*`表示前一个字符出现零次或多次,`+`表示一次或多次,`?`表示零次或一次...
通过使用正则表达式练习器,初学者可以系统地学习正则表达式,而经验丰富的用户也可以检验和优化自己的正则表达式技能,提升在实际项目中的应用能力。在编程、数据分析、Web开发等领域,掌握正则表达式都能带来显著...
在Delphi编程环境中,正则表达式是一种强大的文本处理工具,用于执行模式匹配和字符串操作。本篇文章将详细探讨在Delphi下使用...在实践中不断探索和学习,你将成为正则表达式的高手,为你的项目添加更多功能和价值。
Python正则表达式是Python编程语言中的一个强大...在实际项目中,根据需求组合使用各种正则表达式功能,可以完成复杂的文本分析任务。通过阅读《Python正则表达式基础》PDF文档,可以深入理解这些概念并进行实践操作。