免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1255 | 回复: 0
打印 上一主题 下一主题

正则表达式后向引用详解 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-09-04 14:26 |只看该作者 |倒序浏览
                               正则表达式后向引用详解
反向引用,指把匹配出来的组引用到表达式本身其它地方,比如,在匹配HTML的标记时,我们匹配出一个<a>,我们要把匹配出来的a引用出来,用来找到</a>,这个时候就要用到反向引用。
  语法
  a、反向引用编号的组,语法为\number
  b、反向引用命名的组,语法为\k<name>
反向引用提供查找重复字符组的方便的方法。它们可被认为是再次匹配同一个字符串的快捷指令。
例如,若要查找重复且相邻的字符(如单词“tall”中的两个 L),可以使用正则表达式 (?\w)\k,该正则表达式使用元字符 \w 来查找任何单个单词的字符。分组构造 (? ) 将元字符括在其中,以强制正则表达式引擎记住子表达式匹配(在此示例中将是任意单个字符),并以名称“char”保存它。反向引用构造 \k 使引擎对当前字符和以名称“char”存储的先前匹配字符进行比较。只要单个字符与其前面的字符相同,整个正则表达式就可以找到一个匹配。
要找到重复的全字,您可以修改该分组子表达式,以搜索前面是空格的任何字符组,而不是只搜索任意单个字符。可以用匹配任何字符组的子表达式 \w+ 替换元字符 \w,并使用元字符 \s 匹配字符分组前的空格。这就生成了正则表达式 (?\s\w+)\k,该正则表达式查找任何重复的全字(例如“the the”),但也会匹配指定字符串的其他重复情况,例如词组“the theory”中的重复情况。
为验证上述第二种匹配是以单词为边界的,可以将元字符 \b 添加到重复匹配的后面。所生成的正则表达式 (?\s\w+)\k\b 只查找重复的、前面有空格的全字。
分析反向引用
表达式 \1 到 \9 总是指反向引用,而不是八进制代码。多位表达式 \11 和更高位表达式在具有与该号码对应的反向引用时被视作反向引用;否则,它们会被解释为八进制代码(除非起始位是 8 或 9,在这种情况下它们被视为原义的“8”和“9”)。如果正则表达式包含对未定义的组成员的反向引用,则它被视作分析错误。如果有多义性问题,可以使用 \k 表示法,该表示法是明确的,并且不会与八进制符号代码混淆;同样,诸如 \xdd 等的十六进制代码也是明确的,并且不会与反向引用混淆。

ECMAScript
选项标志被启用时,反向引用行为将稍有不同。有关更多信息,请参见
ECMAScript 与规范化匹配行为

匹配反向引用
反向引用引用组的最近的定义(当从左到右匹配时,最靠近左侧的定义)。具体地讲,就是当组建立多个捕获时,反向引用引用最近的捕获。例如,(?a)(?\1b)* 使用捕获模式 (a)(ab)(abb) 来匹配 aababb。循环限定符不清除组定义。
如果一个组尚未捕获任何子字符串,则对该组的反向引用是未定义的并且永远不匹配。例如,表达式 \1() 永远不匹配任何字符串,但是表达式 ()\1 匹配空字符串。
举例
  a、匹配成对的HTML标签
@"<(?<tag>[^\s>]+)[^>]*>.*</\k<tag>>"
  b、匹配两个两个重叠出现的字符
public static void Main()
{
string s = "aabbc11asd";
Regex reg = new Regex(@"(\w)\1");
MatchCollection matches = reg.Matches(s);
foreach(Match m in matches)
Console.WriteLine(m.Value);
Console.ReadLine();
}
  返回结果为aa bb 11
  辅助匹配组
  以下几种组结构,括号中的Pattern都不作为匹配结果的一部分进行保存
  1、正声明(?=)
  涵义:括号中的模式必须出现在声明右侧,但不作为匹配的一部分
public static void Main()
{
string s = "C#.net,VB.net,PHP,Java,JScript.net";
Regex reg = new Regex(@"[\w\#]+(?=\.net)",RegexOptions.Compiled);
MatchCollection mc = reg.Matches(s);
foreach(Match m in mc)
Console.WriteLine(m.Value);
Console.ReadLine();
//输出 C# VB JScript
}
  可以看到匹配引擎要求匹配.net,但却不把.net放到匹配结果中
  2、负声明(?!)
  涵义:括号中的模式必须不出现在声明右侧
  下例演示如何取得一个<a>标签对中的全部内容,即使其中包含别的HTML tag。
public static void Main()
{
string newsContent = @"url:<a href=""1.html""><img src=""1.gif"">test<span style=""color:red;"">Regex</span></a>.";
Regex regEnd = new Regex(@"<\s*a[^>]*>([^<]|<(?!/a))*<\s*/a\s*>",RegexOptions.Multiline);
Console.WriteLine(regEnd.Match(newsContent).Value);
//Result: <a href="1.html"><img src="1.gif">test<span style="color:red;">Regex</span></a>
Console.ReadLine();
}
  3、反向正声明(?<=)
  涵义:括号中的模式必须出现在声明左侧,但不作为匹配的一部分
  4、反向负声明(?<!)
  涵义:括号中的模式必须不出现在声明左侧
  非回溯匹配
  语法:(?>)
  涵义:该组匹配后,其匹配的字符不能通过回溯用于后面的表达式的匹配。呵呵,光看这句话肯定搞不懂,我当初为了搞懂这个也花了不少的时间,还是通过实例来说明吧:
"www.csdn.net" 可以通过@"\w+\.(.*)\.\w+"来匹配,却不能通过@"\w+\.(?>.*)\.\w+"来匹配!为什么呢?
  原因是正则匹配是贪婪的,匹配时它会尽可能多的匹配最多的结果,所以,上例两个正则式中的.*都会把csdn.net匹配完, 这个时候,第一个表达式在开始匹配时发现\.\w+没得字符给它匹配了,所以它会进行回溯,所谓回溯,就是把.*匹配的结果往回推,回推留出来的字符再用来匹配\.\w+,直到\.\w+匹配成功,整个表达式返回成功的匹配结果。而第二个表达式,因使用的是非回溯匹配,所以,.*匹配完后,不允许通过回溯来匹配\.\w+,所以整个表达式匹配失败。
  请注意,回溯匹配是很浪费资源的一种匹配方式,所以,请尽量避免您的正则式要通过回溯来成功匹配,如上例,可以换成@"\w+\.([^\.]+\.)+\w+"+"。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/76389/showart_1164320.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP