﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Everything is numbers..</title><link>http://www.cppblog.com/yindmm/</link><description>Fuck the World</description><language>zh-cn</language><lastBuildDate>Sat, 11 Apr 2026 09:11:41 GMT</lastBuildDate><pubDate>Sat, 11 Apr 2026 09:11:41 GMT</pubDate><ttl>60</ttl><item><title>.NET正则表达式使用高级技巧之组的概念</title><link>http://www.cppblog.com/yindmm/archive/2009/07/07/89490.html</link><dc:creator>yindmm</dc:creator><author>yindmm</author><pubDate>Tue, 07 Jul 2009 12:37:00 GMT</pubDate><guid>http://www.cppblog.com/yindmm/archive/2009/07/07/89490.html</guid><wfw:comment>http://www.cppblog.com/yindmm/comments/89490.html</wfw:comment><comments>http://www.cppblog.com/yindmm/archive/2009/07/07/89490.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yindmm/comments/commentRss/89490.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yindmm/services/trackbacks/89490.html</trackback:ping><description><![CDATA[日期：2006年6月2日 作者： 佚名
<p>　　正则表达式中的组是很重要的一个概念，它是我们通向高级正则应用的的桥梁。</p>
<p>　　组的概念 </p>
<p>　　一个正则表达式匹配结果可以分成多个部分，这就是组(Group)的目的。能够灵活的使用组后，你会发现Regex真是很方便，也很强大。 </p>
<p>　　先举个例子 </p>
<p>&#160;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img id=Code_Closed_Image_203555 onclick="this.style.display='none'; Code_Closed_Text_203555.style.display='none'; Code_Open_Image_203555.style.display='inline'; Code_Open_Text_203555.style.display='inline';" height=16 src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" width=11 align=top><img id=Code_Open_Image_203555 style="DISPLAY: none" onclick="this.style.display='none'; Code_Open_Text_203555.style.display='none'; Code_Closed_Image_203555.style.display='inline'; Code_Closed_Text_203555.style.display='inline';" height=16 src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" width=11 align=top><span id=Code_Closed_Text_203555 style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"></span><span id=Code_Open_Text_203555 style="DISPLAY: none"><br><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #008080">&nbsp;1</span><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;Main()&nbsp;<br></span><span style="COLOR: #008080">&nbsp;2</span><span style="COLOR: #000000"><img id=Codehighlighter1_27_425_Open_Image onclick="this.style.display='none'; Codehighlighter1_27_425_Open_Text.style.display='none'; Codehighlighter1_27_425_Closed_Image.style.display='inline'; Codehighlighter1_27_425_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_27_425_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_27_425_Closed_Text.style.display='none'; Codehighlighter1_27_425_Open_Image.style.display='inline'; Codehighlighter1_27_425_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_27_425_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_27_425_Open_Text><span style="COLOR: #000000">{&nbsp;<br></span><span style="COLOR: #008080">&nbsp;3</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;s&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">2005-2-21</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;4</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　Regex&nbsp;reg&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;Regex(</span><span style="COLOR: #000000">@"</span><span style="COLOR: #000000">(?&lt;y&gt;\d{4})-(?&lt;m&gt;\d{1,2})-(?&lt;d&gt;\d{1,2})</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,RegexOptions.Compiled);&nbsp;<br></span><span style="COLOR: #008080">&nbsp;5</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　Match&nbsp;match&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;reg.Match(s);&nbsp;<br></span><span style="COLOR: #008080">&nbsp;6</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;year&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">.Parse(match.Groups[</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">y</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">].Value);&nbsp;<br></span><span style="COLOR: #008080">&nbsp;7</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;month&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">.Parse(match.Groups[</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">m</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">].Value);&nbsp;<br></span><span style="COLOR: #008080">&nbsp;8</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;day&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;.Parse(match.Groups[</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">d</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">].Value);&nbsp;<br></span><span style="COLOR: #008080">&nbsp;9</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　DateTime&nbsp;time&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;DateTime(year,month,day);&nbsp;<br></span><span style="COLOR: #008080">10</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　Console.WriteLine(time);&nbsp;<br></span><span style="COLOR: #008080">11</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　Console.ReadLine();&nbsp;<br></span><span style="COLOR: #008080">12</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">&nbsp;&nbsp;<br></span><span style="COLOR: #008080">13</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br></span><span style="COLOR: #008080">14</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></span></div>
<p>　　以上的例子通过组来实现分析一个字符串，并把其转化为一个DateTime实例，当然，这个功能用DateTime.Parse方法就能很方便的实现。 </p>
<p>　　在这个例子中，我把一次Match结果用(?&lt;name&gt;)的方式分成三个组"y","m","d"分别代表年、月、日。 </p>
<p>　　现在我们已经有了组的概念了，再来看如何分组，很简单的，除了上在的办法，我们可以用一对括号就定义出一个组，比如上例可以改成： </p>
<p>&#160;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img id=Code_Closed_Image_203634 onclick="this.style.display='none'; Code_Closed_Text_203634.style.display='none'; Code_Open_Image_203634.style.display='inline'; Code_Open_Text_203634.style.display='inline';" height=16 src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" width=11 align=top><img id=Code_Open_Image_203634 style="DISPLAY: none" onclick="this.style.display='none'; Code_Open_Text_203634.style.display='none'; Code_Closed_Image_203634.style.display='inline'; Code_Closed_Text_203634.style.display='inline';" height=16 src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" width=11 align=top><span id=Code_Closed_Text_203634 style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"></span><span id=Code_Open_Text_203634 style="DISPLAY: none"><br><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #008080">&nbsp;1</span><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;Main()&nbsp;<br></span><span style="COLOR: #008080">&nbsp;2</span><span style="COLOR: #000000"><img id=Codehighlighter1_27_407_Open_Image onclick="this.style.display='none'; Codehighlighter1_27_407_Open_Text.style.display='none'; Codehighlighter1_27_407_Closed_Image.style.display='inline'; Codehighlighter1_27_407_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_27_407_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_27_407_Closed_Text.style.display='none'; Codehighlighter1_27_407_Open_Image.style.display='inline'; Codehighlighter1_27_407_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_27_407_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_27_407_Open_Text><span style="COLOR: #000000">{&nbsp;<br></span><span style="COLOR: #008080">&nbsp;3</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;s&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">2005-2-21</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;4</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　Regex&nbsp;reg&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;Regex(</span><span style="COLOR: #000000">@"</span><span style="COLOR: #000000">(\d{4})-(\d{1,2})-(\d{1,2})</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,RegexOptions.Compiled);&nbsp;<br></span><span style="COLOR: #008080">&nbsp;5</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　Match&nbsp;match&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;reg.Match(s);&nbsp;<br></span><span style="COLOR: #008080">&nbsp;6</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;year&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">.Parse(match.Groups[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">].Value);&nbsp;<br></span><span style="COLOR: #008080">&nbsp;7</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;month&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">.Parse(match.Groups[</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">].Value);&nbsp;<br></span><span style="COLOR: #008080">&nbsp;8</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;day&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;.Parse(match.Groups[</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">].Value);&nbsp;<br></span><span style="COLOR: #008080">&nbsp;9</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　DateTime&nbsp;time&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;DateTime(year,month,day);&nbsp;<br></span><span style="COLOR: #008080">10</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　Console.WriteLine(time);&nbsp;<br></span><span style="COLOR: #008080">11</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　Console.ReadLine();&nbsp;<br></span><span style="COLOR: #008080">12</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">&nbsp;<br></span><span style="COLOR: #008080">13</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br></span><span style="COLOR: #008080">14</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></span></div>
<p>　　从上例可以看出，第一个括号对包涵的组被自动编号为1,后面的括号依次编号为2、3&#8230;&#8230; </p>
<p>&#160;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img id=Code_Closed_Image_203647 onclick="this.style.display='none'; Code_Closed_Text_203647.style.display='none'; Code_Open_Image_203647.style.display='inline'; Code_Open_Text_203647.style.display='inline';" height=16 src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" width=11 align=top><img id=Code_Open_Image_203647 style="DISPLAY: none" onclick="this.style.display='none'; Code_Open_Text_203647.style.display='none'; Code_Closed_Image_203647.style.display='inline'; Code_Closed_Text_203647.style.display='inline';" height=16 src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" width=11 align=top><span id=Code_Closed_Text_203647 style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"></span><span id=Code_Open_Text_203647 style="DISPLAY: none"><br><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #008080">&nbsp;1</span><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;Main()&nbsp;<br></span><span style="COLOR: #008080">&nbsp;2</span><span style="COLOR: #000000"><img id=Codehighlighter1_27_419_Open_Image onclick="this.style.display='none'; Codehighlighter1_27_419_Open_Text.style.display='none'; Codehighlighter1_27_419_Closed_Image.style.display='inline'; Codehighlighter1_27_419_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_27_419_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_27_419_Closed_Text.style.display='none'; Codehighlighter1_27_419_Open_Image.style.display='inline'; Codehighlighter1_27_419_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_27_419_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_27_419_Open_Text><span style="COLOR: #000000">{&nbsp;<br></span><span style="COLOR: #008080">&nbsp;3</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;s&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">2005-2-21</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;4</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　Regex&nbsp;reg&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;Regex(</span><span style="COLOR: #000000">@"</span><span style="COLOR: #000000">(?&lt;2&gt;\d{4})-(?&lt;1&gt;\d{1,2})-(?&lt;3&gt;\d{1,2})</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,RegexOptions.Compiled);&nbsp;<br></span><span style="COLOR: #008080">&nbsp;5</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　Match&nbsp;match&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;reg.Match(s);&nbsp;<br></span><span style="COLOR: #008080">&nbsp;6</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;year&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">.Parse(match.Groups[</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">].Value);&nbsp;<br></span><span style="COLOR: #008080">&nbsp;7</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;month&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">.Parse(match.Groups[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">].Value);&nbsp;<br></span><span style="COLOR: #008080">&nbsp;8</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;day&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;.Parse(match.Groups[</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">].Value);&nbsp;<br></span><span style="COLOR: #008080">&nbsp;9</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　DateTime&nbsp;time&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;DateTime(year,month,day);&nbsp;<br></span><span style="COLOR: #008080">10</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　Console.WriteLine(time);&nbsp;<br></span><span style="COLOR: #008080">11</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　Console.ReadLine();&nbsp;<br></span><span style="COLOR: #008080">12</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">&nbsp;&nbsp;<br></span><span style="COLOR: #008080">13</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br></span><span style="COLOR: #008080">14</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></span></div>
<p>　　再看上例，我们用(?&lt;数字&gt;)的方式手工给每个括号对的组编号，（注意我定义1和2的位置时不是从左到右定义的） </p>
<p>　　通过以上三例，我们知道了给Regex定义Group的三种办法以及相应的引用组匹配结果的方式。 </p>
<p>　　然后，关于组定义，还有两点请注意： </p>
<p>　　1、因为括号用于定义组了，所以如果要匹配"("和")"，请使用"\("和"\)"(关于所有特殊字符的定义，请查看相关Regex expression帮助文档)。 </p>
<p>　　2、如果定义Regex时，使用了ExplicitCapture选项，则第二个例子不会成功，因为此选项要求显式定义了编号或名字的组才捕获并保存结果，如果你没有定义ExplicitCapture选项，而有时又定义了类式于(AB)这样的部分在表达式，而这个(AB)你又并不想捕获结果，那么可以使用&#8220;不捕获的组&#8221;语法，即定义成(?:)的方式，针对于(AB),你可以这样来定义以达到不捕获并保存它到Group集合中的目的－－(?:AB)。</p>
</td>
</tr>
<img src ="http://www.cppblog.com/yindmm/aggbug/89490.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yindmm/" target="_blank">yindmm</a> 2009-07-07 20:37 <a href="http://www.cppblog.com/yindmm/archive/2009/07/07/89490.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出之正则表达式（二）</title><link>http://www.cppblog.com/yindmm/archive/2009/07/07/89485.html</link><dc:creator>yindmm</dc:creator><author>yindmm</author><pubDate>Tue, 07 Jul 2009 11:50:00 GMT</pubDate><guid>http://www.cppblog.com/yindmm/archive/2009/07/07/89485.html</guid><wfw:comment>http://www.cppblog.com/yindmm/comments/89485.html</wfw:comment><comments>http://www.cppblog.com/yindmm/archive/2009/07/07/89485.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yindmm/comments/commentRss/89485.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yindmm/services/trackbacks/89485.html</trackback:ping><description><![CDATA[<span>
<p class=msonormal style="MARGIN: 0in 0in 0pt"><span lang=ZH-CN style="FONT-FAMILY: 宋体">Author:<a href="http://dragon.cnblogs.com/" target=_blank><font color=#b37700>sema</font></a> <br>前言：</span><br>&nbsp;&nbsp;&nbsp; <font face=宋体>本文是前一片文章<a href="http://www.cppblog.com/yindmm/archive/2009/07/07/89484.html">《深入浅出之正则表达式（一）》</a>的续篇，在本文中讲述了正则表达式中的组与向后引用，先前向后查看，条件测试，单词边界，选择符等表达式及例子，并分析了正则引擎在执行匹配时的内部机理。 </font><br>&nbsp;&nbsp;&nbsp; <span lang=ZH-CN style="FONT-FAMILY: 宋体">本文是</span>Jan Goyvaerts<span lang=ZH-CN style="FONT-FAMILY: 宋体">为</span>RegexBuddy<span lang=ZH-CN style="FONT-FAMILY: 宋体">写的教程的译文，版权归原作者所有，欢迎转载。但是为了尊重原作者和译者的劳动，请注明出处！谢谢！</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt"><strong><span style="FONT-SIZE: 18pt"><o:p>&nbsp;<br></o:p></span></strong></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.25in; TEXT-INDENT: -0.25in"></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt"><o:p></o:p></p>
<strong><span><span>9.<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span lang=ZH-CN style="FONT-FAMILY: 宋体">单词边界</span><o:p></o:p></strong>
<p>&nbsp;</p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">元字符</span>&lt;&lt;\b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">也是一种对位置进行匹配的&#8220;锚&#8221;。这种匹配是</span>0<span lang=ZH-CN style="FONT-FAMILY: 宋体">长度匹配。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">有</span>4<span lang=ZH-CN style="FONT-FAMILY: 宋体">种位置被认为是&#8220;单词边界&#8221;：</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 57pt; TEXT-INDENT: -21pt"><span><span>1)<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang=ZH-CN style="FONT-FAMILY: 宋体">在字符串的第一个字符前的位置</span>(<span lang=ZH-CN style="FONT-FAMILY: 宋体">如果字符串的第一个字符是一个&#8220;单词字符&#8221;</span>)</p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 57pt; TEXT-INDENT: -21pt"><span><span>2)<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang=ZH-CN style="FONT-FAMILY: 宋体">在字符串的最后一个字符后的位置</span>(<span lang=ZH-CN style="FONT-FAMILY: 宋体">如果字符串的最后一个字符是一个&#8220;单词字符&#8221;</span>)</p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 57pt; TEXT-INDENT: -21pt"><span><span>3)<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang=ZH-CN style="FONT-FAMILY: 宋体">在一个&#8220;单词字符&#8221;和&#8220;非单词字符&#8221;之间，其中&#8220;非单词字符&#8221;紧跟在&#8220;单词字符&#8221;之后</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 57pt; TEXT-INDENT: -21pt"><span><span>4)<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang=ZH-CN style="FONT-FAMILY: 宋体">在一个&#8220;非单词字符&#8221;和&#8220;单词字符&#8221;之间，其中&#8220;单词字符&#8221;紧跟在&#8220;非单词字符&#8221;后面</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span>&nbsp;</span><span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8220;单词字符&#8221;是可以用&#8220;</span>\w<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;匹配的字符，&#8220;非单词字符&#8221;是可以用&#8220;</span>\W<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;匹配的字符。在大多数的正则表达式实现中，&#8220;单词字符&#8221;通常包括</span>&lt;&lt;[a-zA-Z0-9_]&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">例如：</span>&lt;&lt;\b4\b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">能够匹配单个的</span>4<span lang=ZH-CN style="FONT-FAMILY: 宋体">而不是一个更大数的一部分。这个正则表达式不会匹配&#8220;</span>44<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;中的</span>4<span lang=ZH-CN style="FONT-FAMILY: 宋体">。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">换种说法，几乎可以说</span>&lt;&lt;\b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">匹配一个&#8220;字母数字序列&#8221;的开始和结束的位置。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><o:p>&nbsp;</o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8220;单词边界&#8221;的取反集为</span>&lt;&lt;\B&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">，他要匹配的位置是两个&#8220;单词字符&#8221;之间或者两个&#8220;非单词字符&#8221;之间的位置。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt"><o:p>&nbsp;</o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.3in; TEXT-INDENT: -0.25in"><span style="FONT-FAMILY: Symbol"><span>&#183;<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang=ZH-CN style="FONT-FAMILY: 宋体">深入正则表达式引擎内部</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">让我们看看把正则表达式</span>&lt;&lt;\bis\b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">应用到字符串&#8220;</span>This island is beautiful<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。引擎先处理符号</span>&lt;&lt;\b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。因为</span>\b<span lang=ZH-CN style="FONT-FAMILY: 宋体">是</span>0<span lang=ZH-CN style="FONT-FAMILY: 宋体">长度</span><span lang=ZH-CN> </span><span lang=ZH-CN style="FONT-FAMILY: 宋体">，所以第一个字符</span>T<span lang=ZH-CN style="FONT-FAMILY: 宋体">前面的位置会被考察。因为</span>T<span lang=ZH-CN style="FONT-FAMILY: 宋体">是一个&#8220;单词字符&#8221;，而它前面的字符是一个空字符</span>(void)<span lang=ZH-CN style="FONT-FAMILY: 宋体">，所以</span>\b<span lang=ZH-CN style="FONT-FAMILY: 宋体">匹配了单词边界。接着</span>&lt;&lt;i&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">和第一个字符&#8220;</span>T<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;匹配失败。匹配过程继续进行，直到第五个空格符，和第四个字符&#8220;</span>s<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;之间又匹配了</span>&lt;&lt;\b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。然而空格符和</span>&lt;&lt;i&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">不匹配。继续向后，到了第六个字符&#8220;</span>i<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;，和第五个空格字符之间匹配了</span>&lt;&lt;\b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">，然后</span>&lt;&lt;is&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">和第六、第七个字符都匹配了。然而第八个字符和第二个&#8220;单词边界&#8221;不匹配，所以匹配又失败了。到了第</span>13<span lang=ZH-CN style="FONT-FAMILY: 宋体">个字符</span>i<span lang=ZH-CN style="FONT-FAMILY: 宋体">，因为和前面一个空格符形成&#8220;单词边界&#8221;，同时</span>&lt;&lt;is&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">和&#8220;</span>is<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;匹配。引擎接着尝试匹配第二个</span>&lt;&lt;\b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。因为第</span>15<span lang=ZH-CN style="FONT-FAMILY: 宋体">个空格符和&#8220;</span>s<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;形成单词边界，所以匹配成功。引擎&#8220;急着&#8221;返回成功匹配的结果。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt"><o:p>&nbsp;</o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.25in; TEXT-INDENT: -0.25in"><strong><span><span>10.<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp; </span></span></span></strong><strong><span lang=ZH-CN style="FONT-FAMILY: 宋体">选择符</span><o:p></o:p></strong></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">正则表达式中&#8220;</span>|<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;表示选择。你可以用选择符匹配多个可能的正则表达式中的一个。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">如果你想搜索文字&#8220;</span>cat<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;或&#8220;</span>dog<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;，你可以用</span>&lt;&lt;cat|dog&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。如果你想有更多的选择，你只要扩展列表</span>&lt;&lt;cat|dog|mouse|fish&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">选择符在正则表达式中具有最低的优先级，也就是说，它告诉引擎要么匹配选择符左边的所有表达式，要么匹配右边的所有表达式。你也可以用圆括号来限制选择符的作用范围。如</span>&lt;&lt;\b(cat|dog)\b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">，这样告诉正则引擎把</span>(cat|dog)<span lang=ZH-CN style="FONT-FAMILY: 宋体">当成一个正则表达式单位来处理。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.3in; TEXT-INDENT: -0.25in"><span style="FONT-FAMILY: Symbol"><span>&#183;<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang=ZH-CN style="FONT-FAMILY: 宋体">注意正则引擎的&#8220;急于表功&#8221;性</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">正则引擎是急切的，当它找到一个有效的匹配时，它会停止搜索。因此在一定条件下，选择符两边的表达式的顺序对结果会有影响。假设你想用正则表达式搜索一个编程语言的函数列表：</span>Get<span lang=ZH-CN style="FONT-FAMILY: 宋体">，</span>GetValue<span lang=ZH-CN style="FONT-FAMILY: 宋体">，</span>Set<span lang=ZH-CN style="FONT-FAMILY: 宋体">或</span>SetValue<span lang=ZH-CN style="FONT-FAMILY: 宋体">。一个明显的解决方案是</span>&lt;&lt;Get|GetValue|Set|SetValue&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。让我们看看当搜索</span>SetValue<span lang=ZH-CN style="FONT-FAMILY: 宋体">时的结果。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">因为</span>&lt;&lt;Get&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">和</span>&lt;&lt;GetValue&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">都失败了，而</span>&lt;&lt;Set&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">匹配成功。因为正则导向的引擎都是&#8220;急切&#8221;的，所以它会返回第一个成功的匹配，就是&#8220;</span>Set<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;，而不去继续搜索是否有其他更好的匹配。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">和我们期望的相反，正则表达式并没有匹配整个字符串。有几种可能的解决办法。一是考虑到正则引擎的&#8220;急切&#8221;性，改变选项的顺序，例如我们使用</span>&lt;&lt;GetValue|Get|SetValue|Set&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">，这样我们就可以优先搜索最长的匹配。我们也可以把四个选项结合起来成两个选项：</span>&lt;&lt;Get(Value)?|Set(Value)?&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。因为问号重复符是贪婪的，所以</span>SetValue<span lang=ZH-CN style="FONT-FAMILY: 宋体">总会在</span>Set<span lang=ZH-CN style="FONT-FAMILY: 宋体">之前被匹配。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">一个更好的方案是使用单词边界：</span>&lt;&lt;\b(Get|GetValue|Set|SetValue)\b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">或</span>&lt;&lt;\b(Get(Value)?|Set(Value)?\b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。更进一步，既然所有的选择都有相同的结尾，我们可以把正则表达式优化为</span>&lt;&lt;\b(Get|Set)(Value)?\b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt"><o:p>&nbsp;</o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt"><o:p>&nbsp;</o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.25in; TEXT-INDENT: -0.25in"><strong><span><span>11.<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp; </span></span></span></strong><strong><span lang=ZH-CN style="FONT-FAMILY: 宋体">组与向后引用</span><o:p></o:p></strong></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">把正则表达式的一部分放在圆括号内，你可以将它们形成组。然后你可以对整个组使用一些正则操作，例如重复操作符。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">要注意的是，只有圆括号&#8220;</span>()<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;才能用于形成组。&#8220;</span>[]<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;用于定义字符集。&#8220;</span>{}<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;用于定义重复操作。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">当用&#8220;</span>()<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;定义了一个正则表达式组后，正则引擎则会把被匹配的组按照顺序编号，存入缓存。当对被匹配的组进行向后引用的时候，可以用&#8220;</span>\<span lang=ZH-CN style="FONT-FAMILY: 宋体">数字&#8221;的方式进行引用。</span>&lt;&lt;\1&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">引用第一个匹配的后向引用组，</span>&lt;&lt;\2&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">引用第二个组，以此类推，</span>&lt;&lt;\n&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">引用第</span>n<span lang=ZH-CN style="FONT-FAMILY: 宋体">个组。而</span>&lt;&lt;\0&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">则引用整个被匹配的正则表达式本身。我们看一个例子。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">假设你想匹配一个</span>HTML<span lang=ZH-CN style="FONT-FAMILY: 宋体">标签的开始标签和结束标签，以及标签中间的文本。比如</span>&lt;B&gt;This is a test&lt;/B&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">，我们要匹配</span>&lt;B&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">和</span>&lt;/B&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">以及中间的文字。我们可以用如下正则表达式：&#8220;</span>&lt;([A-Z][A-Z0-9]*)[^&gt;]*&gt;.*?&lt;/\1&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">首先，&#8220;</span>&lt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;将会匹配&#8220;</span>&lt;B&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;的第一个字符&#8220;</span>&lt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。然后</span>[A-Z]<span lang=ZH-CN style="FONT-FAMILY: 宋体">匹配</span>B<span lang=ZH-CN style="FONT-FAMILY: 宋体">，</span>[A-Z0-9]*<span lang=ZH-CN style="FONT-FAMILY: 宋体">将会匹配</span>0<span lang=ZH-CN style="FONT-FAMILY: 宋体">到多次字母数字，后面紧接着</span>0<span lang=ZH-CN style="FONT-FAMILY: 宋体">到多个非&#8220;</span>&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;的字符。最后正则表达式的&#8220;</span>&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;将会匹配&#8220;</span>&lt;B&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;的&#8220;</span>&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。接下来正则引擎将对结束标签之前的字符进行惰性匹配，直到遇到一个&#8220;</span>&lt;/<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;符号。然后正则表达式中的&#8220;</span>\1<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;表示对前面匹配的组&#8220;</span>([A-Z][A-Z0-9]*)<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;进行引用，在本例中，被引用的是标签名&#8220;</span>B<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。所以需要被匹配的结尾标签为&#8220;</span>&lt;/B&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;</span><o:p></o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">你可以对相同的后向引用组进行多次引用，</span>&lt;&lt;([a-c])x\1x\1&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">将匹配&#8220;</span>axaxa<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;、&#8220;</span>bxbxb<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;以及&#8220;</span>cxcxc<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。如果用数字形式引用的组没有有效的匹配，则引用到的内容简单的为空。</span><o:p></o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">一个后向引用不能用于它自身。</span>&lt;&lt;([abc]\1)&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">是错误的。因此你不能将</span>&lt;&lt;\0&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">用于一个正则表达式匹配本身，它只能用于替换操作中。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">后向引用不能用于字符集内部。</span>&lt;&lt;(a)[\1b]&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">中的</span>&lt;&lt;\1&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">并不表示后向引用。在字符集内部，</span>&lt;&lt;\1&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">可以被解释为八进制形式的转码。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">向后引用会降低引擎的速度，因为它需要存储匹配的组。如果你不需要向后引用，你可以告诉引擎对某个组不存储。例如：</span>&lt;&lt;Get(?:Value)&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。其中&#8220;</span>(<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;后面紧跟的&#8220;</span>?:<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;会告诉引擎对于组</span>(Value)<span lang=ZH-CN style="FONT-FAMILY: 宋体">，不存储匹配的值以供后向引用。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.3in; TEXT-INDENT: -0.25in"><span style="FONT-FAMILY: Symbol"><span>&#183;<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang=ZH-CN style="FONT-FAMILY: 宋体">重复操作与后向引用</span><o:p></o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">当对组使用重复操作符时，缓存里后向引用内容会被不断刷新，只保留最后匹配的内容。例如：</span>&lt;&lt;([abc]+)=\1&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">将匹配&#8220;</span>cab=cab<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;，但是</span>&lt;&lt;([abc])+=\1&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">却不会。因为</span>([abc])<span lang=ZH-CN style="FONT-FAMILY: 宋体">第一次匹配&#8220;</span>c<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;时，&#8220;</span>\1<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;代表&#8220;</span>c<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;；然后</span>([abc])<span lang=ZH-CN style="FONT-FAMILY: 宋体">会继续匹配&#8220;</span>a<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;和&#8220;</span>b<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。最后&#8220;</span>\1<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;代表&#8220;</span>b<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;，所以它会匹配&#8220;</span>cab=b<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">应用：检查重复单词</span>--<span lang=ZH-CN style="FONT-FAMILY: 宋体">当编辑文字时，很容易就会输入重复单词，例如&#8220;</span>the the<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。使用</span>&lt;&lt;\b(\w+)\s+\1\b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">可以检测到这些重复单词。要删除第二个单词，只要简单的利用替换功能替换掉&#8220;</span>\1<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;就可以了。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt"><o:p>&nbsp;</o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt"><o:p>&nbsp;</o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.3in; TEXT-INDENT: -0.25in"><span style="FONT-FAMILY: Symbol"><span>&#183;<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang=ZH-CN style="FONT-FAMILY: 宋体">组的命名和引用</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">在</span>PHP<span lang=ZH-CN style="FONT-FAMILY: 宋体">，</span>Python<span lang=ZH-CN style="FONT-FAMILY: 宋体">中，可以用</span>&lt;&lt;(?P&lt;name&gt;group)&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">来对组进行命名。在本例中，词法</span>?P&lt;name&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">就是对组</span>(group)<span lang=ZH-CN style="FONT-FAMILY: 宋体">进行了命名。其中</span>name<span lang=ZH-CN style="FONT-FAMILY: 宋体">是你对组的起的名字。你可以用</span>(?P=name)<span lang=ZH-CN style="FONT-FAMILY: 宋体">进行引用。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in">.NET<span lang=ZH-CN style="FONT-FAMILY: 宋体">的命名组</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in">.NET framework<span lang=ZH-CN style="FONT-FAMILY: 宋体">也支持命名组。不幸的是，微软的程序员们决定发明他们自己的语法，而不是沿用</span>Perl<span lang=ZH-CN style="FONT-FAMILY: 宋体">、</span>Python<span lang=ZH-CN style="FONT-FAMILY: 宋体">的规则。目前为止，还没有任何其他的正则表达式实现支持微软发明的语法。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">下面是</span>.NET<span lang=ZH-CN style="FONT-FAMILY: 宋体">中的例子：</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in">(?&lt;first&gt;group)(?&#8217;second&#8217;group)</p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">正如你所看到的，</span>.NET<span lang=ZH-CN style="FONT-FAMILY: 宋体">提供两种词法来创建命名组：一是用尖括号&#8220;</span>&lt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;，或者用单引号&#8220;</span>&#8217;&#8217;<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。尖括号在字符串中使用更方便，单引号在</span>ASP<span lang=ZH-CN style="FONT-FAMILY: 宋体">代码中更有用，因为</span>ASP<span lang=ZH-CN style="FONT-FAMILY: 宋体">代码中&#8220;</span>&lt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;被用作</span>HTML<span lang=ZH-CN style="FONT-FAMILY: 宋体">标签。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">要引用一个命名组，使用</span>\k&lt;name&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">或</span>\k&#8217;name&#8217;.</p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">当进行搜索替换时，你可以用&#8220;</span>${name}<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;来引用一个命名组。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt"><o:p>&nbsp;</o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.25in; TEXT-INDENT: -0.25in"><strong><span><span>12.<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp; </span></span></span></strong><strong><span lang=ZH-CN style="FONT-FAMILY: 宋体">正则表达式的匹配模式</span><o:p></o:p></strong></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">本教程所讨论的正则表达式引擎都支持三种匹配模式：</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in">&lt;&lt;/i&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">使正则表达式对大小写不敏感，</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in">&lt;&lt;/s&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">开启&#8220;单行模式&#8221;，即点号&#8220;</span>.<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;匹配新行符</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in">&lt;&lt;/m&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">开启&#8220;多行模式&#8221;，即&#8220;</span>^<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;和&#8220;</span>$<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;匹配新行符的前面和后面的位置。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt"><o:p>&nbsp;</o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.3in; TEXT-INDENT: -0.25in"><span style="FONT-FAMILY: Symbol"><span>&#183;<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang=ZH-CN style="FONT-FAMILY: 宋体">在正则表达式内部打开或关闭模式</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">如果你在正则表达式内部插入修饰符</span>(?ism)<span lang=ZH-CN style="FONT-FAMILY: 宋体">，则该修饰符只对其右边的正则表达式起作用。</span>(?-i)<span lang=ZH-CN style="FONT-FAMILY: 宋体">是关闭大小写不敏感。你可以很快的进行测试。</span>&lt;&lt;(?i)te(?-i)st&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">应该匹配</span>TEst<span lang=ZH-CN style="FONT-FAMILY: 宋体">，但是不能匹配</span>teST<span lang=ZH-CN style="FONT-FAMILY: 宋体">或</span>TEST.</p>
<p class=msonormal style="MARGIN: 0in 0in 0pt"><o:p>&nbsp;</o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.25in; TEXT-INDENT: -0.25in"><strong><span><span>13.<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp; </span></span></span></strong><strong><span lang=ZH-CN style="FONT-FAMILY: 宋体">原子组与防止回溯</span><o:p></o:p></strong></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">在一些特殊情况下，因为回溯会使得引擎的效率极其低下。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">让我们看一个例子：要匹配这样的字串，字串中的每个字段间用逗号做分隔符，第</span>12<span lang=ZH-CN style="FONT-FAMILY: 宋体">个字段由</span>P<span lang=ZH-CN style="FONT-FAMILY: 宋体">开头。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">我们容易想到这样的正则表达式</span>&lt;&lt;^(.*?,){11}P&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。这个正则表达式在正常情况下工作的很好。但是在极端情况下，如果第</span>12<span lang=ZH-CN style="FONT-FAMILY: 宋体">个字段不是由</span>P<span lang=ZH-CN style="FONT-FAMILY: 宋体">开头，则会发生灾难性的回溯。如要搜索的字串为&#8220;</span>1,2,3,4,5,6,7,8,9,10,11,12,13<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。首先，正则表达式一直成功匹配直到第</span>12<span lang=ZH-CN style="FONT-FAMILY: 宋体">个字符。这时，前面的正则表达式消耗的字串为&#8220;</span>1,2,3,4,5,6,7,8,9,10,11,<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;，到了下一个字符，</span>&lt;&lt;P&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">并不匹配&#8220;</span>12<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。所以引擎进行回溯，这时正则表达式消耗的字串为&#8220;</span>1,2,3,4,5,6,7,8,9,10,11<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。继续下一次匹配过程，下一个正则符号为点号</span>&lt;&lt;.&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">，可以匹配下一个逗号&#8220;</span>,<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。然而</span>&lt;&lt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">，</span>&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">并不匹配字符&#8220;</span>12<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;中的&#8220;</span>1<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。匹配失败，继续回溯。大家可以想象，这样的回溯组合是个非常大的数量。因此可能会造成引擎崩溃。</span><o:p></o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">用于阻止这样巨大的回溯有几种方案：</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">一种简单的方案是尽可能的使匹配精确。用取反字符集代替点号。例如我们用如下正则表达式</span>&lt;&lt;^([^,\r\n]*,){11}P&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">，这样可以使失败回溯的次数下降到</span>11<span lang=ZH-CN style="FONT-FAMILY: 宋体">次。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">另一种方案是使用原子组。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">原子组的目的是使正则引擎失败的更快一点。因此可以有效的阻止海量回溯。原子组的语法是</span>&lt;&lt;(?&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">正则表达式</span>)&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。位于</span>(?&gt;)<span lang=ZH-CN style="FONT-FAMILY: 宋体">之间的所有正则表达式都会被认为是一个单一的正则符号。一旦匹配失败，引擎将会回溯到原子组前面的正则表达式部分。前面的例子用原子组可以表达成</span>&lt;&lt;^(?&gt;(.*?,){11})P&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。一旦第十二个字段匹配失败，引擎回溯到原子组前面的</span>&lt;&lt;^&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt"><o:p>&nbsp;</o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.25in; TEXT-INDENT: -0.25in"><strong><span><span>14.<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp; </span></span></span></strong><strong><span lang=ZH-CN style="FONT-FAMILY: 宋体">向前查看与向后查看</span><o:p></o:p></strong></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in">Perl 5 <span lang=ZH-CN style="FONT-FAMILY: 宋体">引入了两个强大的正则语法：&#8220;向前查看&#8221;和&#8220;向后查看&#8221;。他们也被称作&#8220;零长度断言&#8221;。他们和锚定一样都是零长度的（所谓零长度即指该正则表达式不消耗被匹配的字符串）。不同之处在于&#8220;前后查看&#8221;会实际匹配字符，只是他们会抛弃匹配只返回匹配结果：匹配或不匹配。这就是为什么他们被称作&#8220;断言&#8221;。他们并不实际消耗字符串中的字符，而只是断言一个匹配是否可能。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">几乎本文讨论的所有正则表达式的实现都支持&#8220;向前向后查看&#8221;。唯一的一个例外是</span>Javascript<span lang=ZH-CN style="FONT-FAMILY: 宋体">只支持向前查看。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.3in; TEXT-INDENT: -0.25in"><span style="FONT-FAMILY: Symbol"><span>&#183;<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang=ZH-CN style="FONT-FAMILY: 宋体">肯定和否定式的向前查看</span><o:p></o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">如我们前面提过的一个例子：要查找一个</span>q<span lang=ZH-CN style="FONT-FAMILY: 宋体">，后面没有紧跟一个</span>u<span lang=ZH-CN style="FONT-FAMILY: 宋体">。也就是说，要么</span>q<span lang=ZH-CN style="FONT-FAMILY: 宋体">后面没有字符，要么后面的字符不是</span>u<span lang=ZH-CN style="FONT-FAMILY: 宋体">。采用否定式向前查看后的一个解决方案为</span>&lt;&lt;q(?!u)&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。否定式向前查看的语法是</span>&lt;&lt;(?!<span lang=ZH-CN style="FONT-FAMILY: 宋体">查看的内容</span>)&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">肯定式向前查看和否定式向前查看很类似：</span>&lt;&lt;(?=<span lang=ZH-CN style="FONT-FAMILY: 宋体">查看的内容</span>)&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">如果在&#8220;查看的内容&#8221;部分有组，也会产生一个向后引用。但是向前查看本身并不会产生向后引用，也不会被计入向后引用的编号中。这是因为向前查看本身是会被抛弃掉的，只保留匹配与否的判断结果。如果你想保留匹配的结果作为向后引用，你可以用</span>&lt;&lt;(?=(regex))&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">来产生一个向后引用。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.3in; TEXT-INDENT: -0.25in"><span style="FONT-FAMILY: Symbol"><span>&#183;<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang=ZH-CN style="FONT-FAMILY: 宋体">肯定和否定式的先后查看</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">向后查看和向前查看有相同的效果，只是方向相反</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">否定式向后查看的语法是：</span>&lt;&lt;(?&lt;!<span lang=ZH-CN style="FONT-FAMILY: 宋体">查看内容</span>)&gt;&gt;</p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">肯定式向后查看的语法是：</span>&lt;&lt;(?&lt;=<span lang=ZH-CN style="FONT-FAMILY: 宋体">查看内容</span>)&gt;&gt;</p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">我们可以看到，和向前查看相比，多了一个表示方向的左尖括号。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">例：</span>&lt;&lt;(?&lt;!a)b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">将会匹配一个没有&#8220;</span>a<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;作前导字符的&#8220;</span>b<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">值得注意的是：向前查看从当前字符串位置开始对&#8220;查看&#8221;正则表达式进行匹配；向后查看则从当前字符串位置开始先后回溯一个字符，然后再开始对&#8220;查看&#8221;正则表达式进行匹配。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><o:p>&nbsp;</o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.3in; TEXT-INDENT: -0.25in"><span style="FONT-FAMILY: Symbol"><span>&#183;<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang=ZH-CN style="FONT-FAMILY: 宋体">深入正则表达式引擎内部</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">让我们看一个简单例子。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">把正则表达式</span>&lt;&lt;q(?!u)&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">应用到字符串&#8220;</span>Iraq<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。正则表达式的第一个符号是</span>&lt;&lt;q&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。正如我们知道的，引擎在匹配</span>&lt;&lt;q&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">以前会扫过整个字符串。当第四个字符&#8220;</span>q<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;被匹配后，&#8220;</span>q<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;后面是空字符</span>(void)<span lang=ZH-CN style="FONT-FAMILY: 宋体">。而下一个正则符号是向前查看。引擎注意到已经进入了一个向前查看正则表达式部分。下一个正则符号是</span>&lt;&lt;u&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">，和空字符不匹配，从而导致向前查看里的正则表达式匹配失败。因为是一个否定式的向前查看，意味着整个向前查看结果是成功的。于是匹配结果&#8220;</span>q<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;被返回了。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">我们在把相同的正则表达式应用到&#8220;</span>quit<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。</span>&lt;&lt;q&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">匹配了&#8220;</span>q<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。下一个正则符号是向前查看部分的</span>&lt;&lt;u&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">，它匹配了字符串中的第二个字符&#8220;</span>i<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。引擎继续走到下个字符&#8220;</span>i<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。然而引擎这时注意到向前查看部分已经处理完了，并且向前查看已经成功。于是引擎抛弃被匹配的字符串部分，这将导致引擎回退到字符&#8220;</span>u<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">因为向前查看是否定式的，意味着查看部分的成功匹配导致了整个向前查看的失败，因此引擎不得不进行回溯。最后因为再没有其他的&#8220;</span>q<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;和</span>&lt;&lt;q&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">匹配，所以整个匹配失败了。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">为了确保你能清楚地理解向前查看的实现，让我们把</span>&lt;&lt;q(?=u)i&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">应用到&#8220;</span>quit<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。</span>&lt;&lt;q&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">首先匹配&#8220;</span>q<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。然后向前查看成功匹配&#8220;</span>u<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;，匹配的部分被抛弃，只返回可以匹配的判断结果。引擎从字符&#8220;</span>i<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;回退到&#8220;</span>u<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。由于向前查看成功了，引擎继续处理下一个正则符号</span>&lt;&lt;i&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。结果发现</span>&lt;&lt;i&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">和&#8220;</span>u<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;不匹配。因此匹配失败了。由于后面没有其他的&#8220;</span>q<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;，整个正则表达式的匹配失败了。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><o:p>&nbsp;</o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.3in; TEXT-INDENT: -0.25in"><span style="FONT-FAMILY: Symbol"><span>&#183;<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang=ZH-CN style="FONT-FAMILY: 宋体">更进一步理解正则表达式引擎内部机制</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">让我们把</span>&lt;&lt;(?&lt;=a)b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">应用到&#8220;</span>thingamabob<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。引擎开始处理向后查看部分的正则符号和字符串中的第一个字符。在这个例子中，向后查看告诉正则表达式引擎回退一个字符，然后查看是否有一个&#8220;</span>a<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;被匹配。因为在&#8220;</span>t<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;前面没有字符，所以引擎不能回退。因此向后查看失败了。引擎继续走到下一个字符&#8220;</span>h<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。再一次，引擎暂时回退一个字符并检查是否有个&#8220;</span>a<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;被匹配。结果发现了一个&#8220;</span>t<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。向后查看又失败了。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">向后查看继续失败，直到正则表达式到达了字符串中的&#8220;</span>m<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;，于是肯定式的向后查看被匹配了。因为它是零长度的，字符串的当前位置仍然是&#8220;</span>m<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。下一个正则符号是</span>&lt;&lt;b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">，和&#8220;</span>m<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;匹配失败。下一个字符是字符串中的第二个&#8220;</span>a<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。引擎向后暂时回退一个字符，并且发现</span>&lt;&lt;a&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">不匹配&#8220;</span>m<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">在下一个字符是字符串中的第一个&#8220;</span>b<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。引擎暂时性的向后退一个字符发现向后查看被满足了，同时</span>&lt;&lt;b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">匹配了&#8220;</span>b<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。因此整个正则表达式被匹配了。作为结果，正则表达式返回字符串中的第一个&#8220;</span>b<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.3in; TEXT-INDENT: -0.25in"><span style="FONT-FAMILY: Symbol"><span>&#183;<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang=ZH-CN style="FONT-FAMILY: 宋体">向前向后查看的应用</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">我们来看这样一个例子：查找一个具有</span>6<span lang=ZH-CN style="FONT-FAMILY: 宋体">位字符的，含有&#8220;</span>cat<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;的单词。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">首先，我们可以不用向前向后查看来解决问题，例如：</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.5in">&lt;&lt; cat\w{3}|\wcat\w{2}|\w{2}cat\w|\w{3}cat&gt;&gt;</p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">足够简单吧！但是当需求变成查找一个具有</span>6-12<span lang=ZH-CN style="FONT-FAMILY: 宋体">位字符，含有&#8220;</span>cat<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;，&#8220;</span>dog<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;或&#8220;</span>mouse<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;的单词时，这种方法就变得有些笨拙了。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">我们来看看使用向前查看的方案。在这个例子中，我们有两个基本需求要满足：一是我们需要一个</span>6<span lang=ZH-CN style="FONT-FAMILY: 宋体">位的字符，二是单词含有&#8220;</span>cat<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">满足第一个需求的正则表达式为</span>&lt;&lt;\b\w{6}\b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。满足第二个需求的正则表达式为</span>&lt;&lt;\b\w*cat\w*\b&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">把两者结合起来，我们可以得到如下的正则表达式：</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span>&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;&lt;(?=\b\w{6}\b)\b\w*cat\w*\b&gt;&gt;</p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">具体的匹配过程留给读者。但是要注意的一点是，向前查看是不消耗字符的，因此当判断单词满足具有</span>6<span lang=ZH-CN style="FONT-FAMILY: 宋体">个字符的条件后，引擎会从开始判断前的位置继续对后面的正则表达式进行匹配。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">最后作些优化，可以得到下面的正则表达式：</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in">&lt;&lt;\b(?=\w{6}\b)\w{0,3}cat\w*&gt;&gt;<o:p></o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.3in"><o:p>&nbsp;</o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.25in; TEXT-INDENT: -0.25in"><strong><span><span>15.<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp; </span></span></span></strong><strong><span lang=ZH-CN style="FONT-FAMILY: 宋体">正则表达式中的条件测试</span><o:p></o:p></strong></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">条件测试的语法为</span>&lt;&lt;(?ifthen|else)&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">。&#8220;</span>if<span lang=ZH-CN style="FONT-FAMILY: 宋体">&#8221;部分可以是向前向后查看表达式。如果用向前查看，则语法变为：</span>&lt;&lt;(?(?=regex)then|else)&gt;&gt;<span lang=ZH-CN style="FONT-FAMILY: 宋体">，其中</span>else<span lang=ZH-CN style="FONT-FAMILY: 宋体">部分是可选的。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">如果</span>if<span lang=ZH-CN style="FONT-FAMILY: 宋体">部分为</span>true<span lang=ZH-CN style="FONT-FAMILY: 宋体">，则正则引擎会试图匹配</span>then<span lang=ZH-CN style="FONT-FAMILY: 宋体">部分，否则引擎会试图匹配</span>else<span lang=ZH-CN style="FONT-FAMILY: 宋体">部分。</span><o:p></o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">需要记住的是，向前先后查看并不实际消耗任何字符，因此后面的</span>then<span lang=ZH-CN style="FONT-FAMILY: 宋体">与</span>else<span lang=ZH-CN style="FONT-FAMILY: 宋体">部分的匹配时从</span>if<span lang=ZH-CN style="FONT-FAMILY: 宋体">测试前的部分开始进行尝试。</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt"><o:p>&nbsp;</o:p></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt 0.25in; TEXT-INDENT: -0.25in"><strong><span><span>16.<span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp; </span></span></span></strong><strong><span lang=ZH-CN style="FONT-FAMILY: 宋体">为正则表达式添加注释</span><o:p></o:p></strong></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">在正则表达式中添加注释的语法是：</span>&lt;&lt;(?#comment)&gt;&gt;</p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span lang=ZH-CN style="FONT-FAMILY: 宋体">例：为用于匹配有效日期的正则表达式添加注释：</span></p>
<p class=msonormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.25in"><span>&nbsp;</span>(?#year)(19|20)\d\d[- /.](?#month)(0[1-9]|1[012])[- /.](?#day)(0[1-9]|[12][0-9]|3[01])</p>
</span>
<img src ="http://www.cppblog.com/yindmm/aggbug/89485.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yindmm/" target="_blank">yindmm</a> 2009-07-07 19:50 <a href="http://www.cppblog.com/yindmm/archive/2009/07/07/89485.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出之正则表达式（一）</title><link>http://www.cppblog.com/yindmm/archive/2009/07/07/89484.html</link><dc:creator>yindmm</dc:creator><author>yindmm</author><pubDate>Tue, 07 Jul 2009 11:46:00 GMT</pubDate><guid>http://www.cppblog.com/yindmm/archive/2009/07/07/89484.html</guid><wfw:comment>http://www.cppblog.com/yindmm/comments/89484.html</wfw:comment><comments>http://www.cppblog.com/yindmm/archive/2009/07/07/89484.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yindmm/comments/commentRss/89484.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yindmm/services/trackbacks/89484.html</trackback:ping><description><![CDATA[<div class="faq_FAQPartAnswer"><font face="宋体">Author:<a href="http://dragon.cnblogs.com/" target="_blank">sema</a> <br><br>前言：<br></font>&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体;" lang="ZH-CN">半年前我对正则表达式产生了兴趣，在网上查找过不少资料，看过不少的教程，最后在使用一个正则表达式工具</span>RegexBuddy<span style="font-family: 宋体;" lang="ZH-CN">时发现他的教程写的非常好，可以说是我目前见过最好的正则表达式教程。于是一直想把他翻译过来。这个愿望直到这个五一长假才得以实现，结果就有了这篇文章。关于本文的名字，使用</span>&#8220;<span style="font-family: 宋体;" lang="ZH-CN">深入浅出</span>&#8221;<span style="font-family: 宋体;" lang="ZH-CN">似乎已经太俗。但是通读原文以后，觉得只有用</span>&#8220;<span style="font-family: 宋体;" lang="ZH-CN">深入浅出</span>&#8221;<span style="font-family: 宋体;" lang="ZH-CN">才能准确的表达出该教程给我的感受，所以也就不能免俗了。</span><br>&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体;" lang="ZH-CN">本文是</span>Jan Goyvaerts<span style="font-family: 宋体;" lang="ZH-CN">为</span>RegexBuddy<span style="font-family: 宋体;" lang="ZH-CN">写的教程的译文，版权归原作者所有，欢迎转载。但是为了尊重原作者和译者的劳动，请注明出处！谢谢！</span>
<p class="msonormal" style="margin: 0in 0in 0pt;"><strong><span style="font-size: 18pt;"><o:p>&nbsp;</o:p></span></strong></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.25in; text-indent: -0.25in;"><strong><span><span>1.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span style="font-family: 宋体;" lang="ZH-CN">什么是正则表达式</span><o:p></o:p></strong></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">基本说来，正则表达式是一种用来描述一定数量文本的模式。</span>Regex<span style="font-family: 宋体;" lang="ZH-CN">代表</span>Regular Express<span style="font-family: 宋体;" lang="ZH-CN">。本文将用</span>&lt;&lt;regex&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">来表示一段具体的正则表达式。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">一段文本就是最基本的模式，简单的匹配相同的文本。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.25in; text-indent: -0.25in;"><strong><span><span>2.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span style="font-family: 宋体;" lang="ZH-CN">不同的正则表达式引擎</span><o:p></o:p></strong></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">正则表达式引擎是一种可以处理正则表达式的软件。通常，引擎是更大的应用程序的一部分。在软件世界，不同的正则表达式并不互相兼容。本教程会集中讨论</span>Perl 5 <span style="font-family: 宋体;" lang="ZH-CN">类型的引擎，因为这种引擎是应用最广泛的引擎。同时我们也会提到一些和其他引擎的区别。许多近代的引擎都很类似，但不完全一样。例如</span>.NET<span style="font-family: 宋体;" lang="ZH-CN">正则库，</span>JDK<span style="font-family: 宋体;" lang="ZH-CN">正则包。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.25in; text-indent: -0.25in;"><strong><span><span>3.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span style="font-family: 宋体;" lang="ZH-CN">文字符号</span><o:p></o:p></strong></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">最基本的正则表达式由单个文字符号组成。如</span>&lt;&lt;a&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">，它将匹配字符串中第一次出现的字符&#8220;</span>a<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。如对字符串&#8220;</span>Jack is a boy<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。&#8220;</span>J<span style="font-family: 宋体;" lang="ZH-CN">&#8221;后的&#8220;</span>a<span style="font-family: 宋体;" lang="ZH-CN">&#8221;将被匹配。而第二个&#8220;</span>a<span style="font-family: 宋体;" lang="ZH-CN">&#8221;将不会被匹配。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">正则表达式也可以匹配第二个&#8220;</span>a<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，这必须是你告诉正则表达式引擎从第一次匹配的地方开始搜索。在文本编辑器中，你可以使用&#8220;查找下一个&#8221;。在编程语言中，会有一个函数可以使你从前一次匹配的位置开始继续向后搜索。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">类似的，</span>&lt;&lt;cat&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">会匹配&#8220;</span>About cats and dogs<span style="font-family: 宋体;" lang="ZH-CN">&#8221;中的&#8220;</span>cat<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。这等于是告诉正则表达式引擎，找到一个</span>&lt;&lt;c&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">，紧跟一个</span>&lt;&lt;a&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">，再跟一个</span>&lt;&lt;t&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">要注意，正则表达式引擎缺省是大小写敏感的。除非你告诉引擎忽略大小写，否则</span>&lt;&lt;cat&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">不会匹配&#8220;</span>Cat<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: -0.25in;"><span style="font-family: Symbol;"><span>&#183;<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;" lang="ZH-CN">特殊字符</span><o:p></o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">对于文字字符，有</span>11<span style="font-family: 宋体;" lang="ZH-CN">个字符被保留作特殊用途。他们是：</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.5in; text-indent: 0.5in;">[ ] \ ^ $ . | ? * + ( )</p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">这些特殊字符也被称作元字符。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">如果你想在正则表达式中将这些字符用作文本字符，你需要用反斜杠&#8220;</span>\<span style="font-family: 宋体;" lang="ZH-CN">&#8221;对其进行换码</span><span lang="ZH-CN"> </span>(escape)<span style="font-family: 宋体;" lang="ZH-CN">。例如你想匹配&#8220;</span>1+1=2<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，正确的表达式为</span>&lt;&lt;1\+1=2&gt;&gt;.</p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">需要注意的是，</span>&lt;&lt;1+1=2&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">也是有效的正则表达式。但它不会匹配&#8220;</span>1+1=2<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，而会匹配&#8220;</span>123+111=234<span style="font-family: 宋体;" lang="ZH-CN">&#8221;中的&#8220;</span>111=2<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。因为&#8220;</span>+<span style="font-family: 宋体;" lang="ZH-CN">&#8221;在这里表示特殊含义（重复</span>1<span style="font-family: 宋体;" lang="ZH-CN">次到多次）。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">在编程语言中，要注意，一些特殊的字符会先被编译器处理，然后再传递给正则引擎。因此正则表达式</span>&lt;&lt;1\+2=2&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">在</span>C++<span style="font-family: 宋体;" lang="ZH-CN">中要写成&#8220;</span>1\\+1=2<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。为了匹配&#8220;</span>C:\temp<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，你要用正则表达式</span>&lt;&lt;C:\\temp&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">。而在</span>C++<span style="font-family: 宋体;" lang="ZH-CN">中，正则表达式则变成了&#8220;</span>C:\\\\temp<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: -0.25in;"><span style="font-family: Symbol;"><span>&#183;<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;" lang="ZH-CN">不可显示字符</span><o:p></o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">可以使用特殊字符序列来代表某些不可显示字符：</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;">&lt;&lt;\t&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">代表</span>Tab(0x09)</p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;">&lt;&lt;\r&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">代表回车符</span>(0x0D)</p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;">&lt;&lt;\n&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">代表换行符</span>(0x0A)</p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">要注意的是</span>Windows<span style="font-family: 宋体;" lang="ZH-CN">中文本文件使用&#8220;</span>\r\n<span style="font-family: 宋体;" lang="ZH-CN">&#8221;来结束一行而</span>Unix<span style="font-family: 宋体;" lang="ZH-CN">使用&#8220;</span>\n<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.25in; text-indent: -0.25in;"><strong><span><span>4.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span style="font-family: 宋体;" lang="ZH-CN">正则表达式引擎的内部工作机制</span><o:p></o:p></strong></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">知道正则表达式引擎是如何工作的有助于你很快理解为何某个正则表达式不像你期望的那样工作。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">有两种类型的引擎：文本导向</span>(text-directed)<span style="font-family: 宋体;" lang="ZH-CN">的引擎和正则导向</span>(regex-directed)<span style="font-family: 宋体;" lang="ZH-CN">的引擎。</span>Jeffrey Friedl<span style="font-family: 宋体;" lang="ZH-CN">把他们称作</span>DFA<span style="font-family: 宋体;" lang="ZH-CN">和</span>NFA<span style="font-family: 宋体;" lang="ZH-CN">引擎。本文谈到的是正则导向的引擎。这是因为一些非常有用的特性，如&#8220;惰性&#8221;量词</span>(lazy quantifiers)<span style="font-family: 宋体;" lang="ZH-CN">和反向引用</span>(backreferences)<span style="font-family: 宋体;" lang="ZH-CN">，只能在正则导向的引擎中实现。所以毫不意外这种引擎是目前最流行的引擎。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">你可以轻易分辨出所使用的引擎是文本导向还是正则导向。如果反向引用或&#8220;惰性&#8221;量词被实现，则可以肯定你使用的引擎是正则导向的。你可以作如下测试：将正则表达式</span>&lt;&lt;regex|regex not&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">应用到字符串&#8220;</span>regex not<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。如果匹配的结果是</span>regex<span style="font-family: 宋体;" lang="ZH-CN">，则引擎是正则导向的。如果结果是</span>regex not<span style="font-family: 宋体;" lang="ZH-CN">，则是文本导向的。因为正则导向的引擎是&#8220;猴急&#8221;的，它会很急切的进行表功，报告它找到的第一个匹配</span><span lang="ZH-CN"> </span><span style="font-family: 宋体;" lang="ZH-CN">。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: -0.25in;"><span style="font-family: Symbol;"><span>&#183;<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;" lang="ZH-CN">正则导向的引擎总是返回最左边的匹配</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">这是需要你理解的很重要的一点：即使以后有可能发现一个&#8220;更好&#8221;的匹配，正则导向的引擎也总是返回最左边的匹配。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">当把</span>&lt;&lt;cat&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">应用到&#8220;</span>He captured a catfish for his cat<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，引擎先比较</span>&lt;&lt;c&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">和&#8220;</span>H<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，结果失败了。于是引擎再比较</span>&lt;&lt;c&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">和&#8220;</span>e<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，也失败了。直到第四个字符，</span>&lt;&lt;c&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">匹配了&#8220;</span>c<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。</span>&lt;&lt;a&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">匹配了第五个字符。到第六个字符</span>&lt;&lt;t&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">没能匹配&#8220;</span>p<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，也失败了。引擎再继续从第五个字符重新检查匹配性。直到第十五个字符开始，</span>&lt;&lt;cat&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">匹配上了&#8220;</span>catfish<span style="font-family: 宋体;" lang="ZH-CN">&#8221;中的&#8220;</span>cat<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，正则表达式引擎急切的返回第一个匹配的结果，而不会再继续查找是否有其他更好的匹配。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.25in; text-indent: -0.25in;"><strong><span><span>5.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span style="font-family: 宋体;" lang="ZH-CN">字符集</span><o:p></o:p></strong></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">字符集是由一对方括号&#8220;</span>[]<span style="font-family: 宋体;" lang="ZH-CN">&#8221;括起来的字符集合。使用字符集，你可以告诉正则表达式引擎仅仅匹配多个字符中的一个。如果你想匹配一个&#8220;</span>a<span style="font-family: 宋体;" lang="ZH-CN">&#8221;或一个&#8220;</span>e<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，使用</span>&lt;&lt;[ae]&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">。你可以使用</span>&lt;&lt;gr[ae]y&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">匹配</span>gray<span style="font-family: 宋体;" lang="ZH-CN">或</span>grey<span style="font-family: 宋体;" lang="ZH-CN">。这在你不确定你要搜索的字符是采用美国英语还是英国英语时特别有用。相反，</span>&lt;&lt;gr[ae]y&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">将不会匹配</span>graay<span style="font-family: 宋体;" lang="ZH-CN">或</span>graey<span style="font-family: 宋体;" lang="ZH-CN">。字符集中的字符顺序并没有什么关系，结果都是相同的。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">你可以使用连字符&#8220;</span>-<span style="font-family: 宋体;" lang="ZH-CN">&#8221;定义一个字符范围作为字符集。</span>&lt;&lt;[0-9]&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">匹配</span>0<span style="font-family: 宋体;" lang="ZH-CN">到</span>9<span style="font-family: 宋体;" lang="ZH-CN">之间的单个数字。你可以使用不止一个范围。</span>&lt;&lt;[0-9a-fA-F] &gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">匹配单个的十六进制数字，并且大小写不敏感。你也可以结合范围定义与单个字符定义。</span>&lt;&lt;[0-9a-fxA-FX]&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">匹配一个十六进制数字或字母</span>X<span style="font-family: 宋体;" lang="ZH-CN">。再次强调一下，字符和范围定义的先后顺序对结果没有影响。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: -0.25in;"><span style="font-family: Symbol;"><span>&#183;<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;" lang="ZH-CN">字符集的一些应用</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">查找一个可能有拼写错误的单词，比如</span>&lt;&lt;sep[ae]r[ae]te&gt;&gt; <span style="font-family: 宋体;" lang="ZH-CN">或</span><span lang="ZH-CN"> </span>&lt;&lt;li[cs]en[cs]e&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">查找程序语言的标识符，</span>&lt;&lt;A-Za-z_][A-Za-z_0-9]*&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">。</span>(*<span style="font-family: 宋体;" lang="ZH-CN">表示重复</span>0<span style="font-family: 宋体;" lang="ZH-CN">或多次</span>)</p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">查找</span>C<span style="font-family: 宋体;" lang="ZH-CN">风格的十六进制数</span>&lt;&lt;0[xX][A-Fa-f0-9]+&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">。</span>(+<span style="font-family: 宋体;" lang="ZH-CN">表示重复一次或多次</span>)</p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: -0.25in;"><span style="font-family: Symbol;"><span>&#183;<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;" lang="ZH-CN">取反字符集</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">在左方括号&#8220;</span>[<span style="font-family: 宋体;" lang="ZH-CN">&#8221;后面紧跟一个尖括号&#8220;</span>^<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，将会对字符集取反。结果是字符集将匹配任何不在方括号中的字符。不像&#8220;</span>.<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，取反字符集是可以匹配回车换行符的。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">需要记住的很重要的一点是，取反字符集必须要匹配一个字符。</span>&lt;&lt;q[^u]&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">并不意味着：匹配一个</span>q<span style="font-family: 宋体;" lang="ZH-CN">，后面没有</span>u<span style="font-family: 宋体;" lang="ZH-CN">跟着。它意味着：匹配一个</span>q<span style="font-family: 宋体;" lang="ZH-CN">，后面跟着一个不是</span>u<span style="font-family: 宋体;" lang="ZH-CN">的字符。所以它不会匹配&#8220;</span>Iraq<span style="font-family: 宋体;" lang="ZH-CN">&#8221;中的</span>q<span style="font-family: 宋体;" lang="ZH-CN">，而会匹配&#8220;</span>Iraq is a country<span style="font-family: 宋体;" lang="ZH-CN">&#8221;中的</span>q<span style="font-family: 宋体;" lang="ZH-CN">和一个空格符。事实上，空格符是匹配中的一部分，因为它是一个&#8220;不是</span>u<span style="font-family: 宋体;" lang="ZH-CN">的字符&#8221;。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">如果你只想匹配一个</span>q<span style="font-family: 宋体;" lang="ZH-CN">，条件是</span>q<span style="font-family: 宋体;" lang="ZH-CN">后面有一个不是</span>u<span style="font-family: 宋体;" lang="ZH-CN">的字符，我们可以用后面将讲到的向前查看来解决。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: -0.25in;"><span style="font-family: Symbol;"><span>&#183;<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;" lang="ZH-CN">字符集中的元字符</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">需要注意的是，在字符集中只有</span>4<span style="font-family: 宋体;" lang="ZH-CN">个</span><span lang="ZH-CN"> </span><span style="font-family: 宋体;" lang="ZH-CN">字符具有特殊含义。它们是：&#8220;</span>] \ ^ -<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。&#8220;</span>]<span style="font-family: 宋体;" lang="ZH-CN">&#8221;代表字符集定义的结束；&#8220;</span>\<span style="font-family: 宋体;" lang="ZH-CN">&#8221;代表转义；&#8220;</span>^<span style="font-family: 宋体;" lang="ZH-CN">&#8221;代表取反；&#8220;</span>-<span style="font-family: 宋体;" lang="ZH-CN">&#8221;代表范围定义。其他常见的元字符在字符集定义内部都是正常字符，不需要转义。例如，要搜索星号</span>*<span style="font-family: 宋体;" lang="ZH-CN">或加号</span>+<span style="font-family: 宋体;" lang="ZH-CN">，你可以用</span>&lt;&lt;[+*]&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">。当然，如果你对那些通常的元字符进行转义，你的正则表达式一样会工作得很好，但是这会降低可读性。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">在字符集定义中为了将反斜杠&#8220;</span>\<span style="font-family: 宋体;" lang="ZH-CN">&#8221;作为一个文字字符而非特殊含义的字符，你需要用另一个反斜杠对它进行转义。</span>&lt;&lt;[\\x]&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">将会匹配一个反斜杠和一个</span>X<span style="font-family: 宋体;" lang="ZH-CN">。&#8220;</span>]^-<span style="font-family: 宋体;" lang="ZH-CN">&#8221;都可以用反斜杠进行转义，或者将他们放在一个不可能使用到他们特殊含义的位置。我们推荐后者，因为这样可以增加可读性。比如对于字符&#8220;</span>^<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，将它放在除了左括号&#8220;</span>[<span style="font-family: 宋体;" lang="ZH-CN">&#8221;后面的位置，使用的都是文字字符含义而非取反含义。如</span>&lt;&lt;[x^]&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">会匹配一个</span>x<span style="font-family: 宋体;" lang="ZH-CN">或</span>^<span style="font-family: 宋体;" lang="ZH-CN">。</span>&lt;&lt;[]x]&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">会匹配一个&#8220;</span>]<span style="font-family: 宋体;" lang="ZH-CN">&#8221;或&#8220;</span>x<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。</span>&lt;&lt;[-x]&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">或</span>&lt;&lt;[x-]&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">都会匹配一个&#8220;</span>-<span style="font-family: 宋体;" lang="ZH-CN">&#8221;或&#8220;</span>x<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: -0.25in;"><span style="font-family: Symbol;"><span>&#183;<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;" lang="ZH-CN">字符集的简写</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">因为一些字符集非常常用，所以有一些简写方式。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;">&lt;&lt;\d&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">代表</span>&lt;&lt;[0-9]&gt;&gt;;</p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;">&lt;&lt;\w&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">代表单词字符。这个是随正则表达式实现的不同而有些差异。绝大多数的正则表达式实现的单词字符集都包含了</span>&lt;&lt;A-Za-z0-9_]&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;">&lt;&lt;\s&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">代表&#8220;白字符&#8221;。这个也是和不同的实现有关的。在绝大多数的实现中，都包含了空格符和</span>Tab<span style="font-family: 宋体;" lang="ZH-CN">符，以及回车换行符</span>&lt;&lt;\r\n&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">字符集的缩写形式可以用在方括号之内或之外。</span>&lt;&lt;\s\d&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">匹配一个白字符后面紧跟一个数字。</span>&lt;&lt;[\s\d]&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">匹配单个白字符或数字。</span>&lt;&lt;[\da-fA-F]&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">将匹配一个十六进制数字。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">取反字符集的简写</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;">&lt;&lt;[\S]&gt;&gt; = &lt;&lt;[^\s]&gt;&gt;</p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;">&lt;&lt;[\W]&gt;&gt; = &lt;&lt;[^\w]&gt;&gt;</p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;">&lt;&lt;[\D]&gt;&gt; = &lt;&lt;[^\d]&gt;&gt;</p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: -0.25in;"><span style="font-family: Symbol;"><span>&#183;<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;" lang="ZH-CN">字符集的重复</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">如果你用&#8220;</span>?*+<span style="font-family: 宋体;" lang="ZH-CN">&#8221;操作符来重复一个字符集，你将会重复整个字符集。而不仅是它匹配的那个字符。正则表达式</span>&lt;&lt;[0-9]+&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">会匹配</span>837<span style="font-family: 宋体;" lang="ZH-CN">以及</span>222<span style="font-family: 宋体;" lang="ZH-CN">。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">如果你仅仅想重复被匹配的那个字符，可以用向后引用达到目的。我们以后将讲到向后引用。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.25in; text-indent: -0.25in;"><strong><span><span>6.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span style="font-family: 宋体;" lang="ZH-CN">使用</span>?*</strong><strong><span style="font-family: 宋体;" lang="ZH-CN">或</span>+ </strong><strong><span style="font-family: 宋体;" lang="ZH-CN">进行重复</span><o:p></o:p></strong></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;">?<span style="font-family: 宋体;" lang="ZH-CN">：告诉引擎匹配前导字符</span>0<span style="font-family: 宋体;" lang="ZH-CN">次或一次。事实上是表示前导字符是可选的。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;">+<span style="font-family: 宋体;" lang="ZH-CN">：告诉引擎匹配前导字符</span>1<span style="font-family: 宋体;" lang="ZH-CN">次或多次</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;">*<span style="font-family: 宋体;" lang="ZH-CN">：告诉引擎匹配前导字符</span>0<span style="font-family: 宋体;" lang="ZH-CN">次或多次</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;">&lt;[A-Za-z][A-Za-z0-9]*&gt;<span style="font-family: 宋体;" lang="ZH-CN">匹配没有属性的</span>HTML<span style="font-family: 宋体;" lang="ZH-CN">标签，&#8220;</span>&lt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;以及&#8220;</span>&gt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;是文字符号。第一个字符集匹配一个字母，第二个字符集匹配一个字母或数字。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">我们似乎也可以用</span>&lt;[A-Za-z0-9]+&gt;<span style="font-family: 宋体;" lang="ZH-CN">。但是它会匹配</span>&lt;1&gt;<span style="font-family: 宋体;" lang="ZH-CN">。但是这个正则表达式在你知道你要搜索的字符串不包含类似的无效标签时还是足够有效的。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: -0.25in;"><span style="font-family: Symbol;"><span>&#183;<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;" lang="ZH-CN">限制性重复</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">许多现代的正则表达式实现，都允许你定义对一个字符重复多少次。词法是：</span>{min,max}<span style="font-family: 宋体;" lang="ZH-CN">。</span>min<span style="font-family: 宋体;" lang="ZH-CN">和</span>max<span style="font-family: 宋体;" lang="ZH-CN">都是非负整数。如果逗号有而</span>max<span style="font-family: 宋体;" lang="ZH-CN">被忽略了，则</span>max<span style="font-family: 宋体;" lang="ZH-CN">没有限制。如果逗号和</span>max<span style="font-family: 宋体;" lang="ZH-CN">都被忽略了，则重复</span>min<span style="font-family: 宋体;" lang="ZH-CN">次。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">因此</span>{0,}<span style="font-family: 宋体;" lang="ZH-CN">和</span>*<span style="font-family: 宋体;" lang="ZH-CN">一样，</span>{1<span style="font-family: 宋体;" lang="ZH-CN">，</span>}<span style="font-family: 宋体;" lang="ZH-CN">和</span>+ <span style="font-family: 宋体;" lang="ZH-CN">的作用一样。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">你可以用</span>&lt;&lt;\b[1-9][0-9]{3}\b&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">匹配</span>1000~9999<span style="font-family: 宋体;" lang="ZH-CN">之间的数字</span>(<span style="font-family: 宋体;" lang="ZH-CN">&#8220;</span>\b<span style="font-family: 宋体;" lang="ZH-CN">&#8221;表示单词边界</span>)<span style="font-family: 宋体;" lang="ZH-CN">。</span>&lt;&lt;\b[1-9][0-9]{2,4}\b&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">匹配一个在</span>100~99999<span style="font-family: 宋体;" lang="ZH-CN">之间的数字。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: 0.3in;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: -0.25in;"><span style="font-family: Symbol;"><span>&#183;<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;" lang="ZH-CN">注意贪婪性</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">假设你想用一个正则表达式匹配一个</span>HTML<span style="font-family: 宋体;" lang="ZH-CN">标签。你知道输入将会是一个有效的</span>HTML<span style="font-family: 宋体;" lang="ZH-CN">文件，因此正则表达式不需要排除那些无效的标签。所以如果是在两个尖括号之间的内容，就应该是一个</span>HTML<span style="font-family: 宋体;" lang="ZH-CN">标签。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">许多正则表达式的新手会首先想到用正则表达式</span>&lt;&lt; &lt;.+&gt; &gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">，他们会很惊讶的发现，对于测试字符串，&#8220;</span>This is a &lt;EM&gt;first&lt;/EM&gt; test<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，你可能期望会返回</span>&lt;EM&gt;<span style="font-family: 宋体;" lang="ZH-CN">，然后继续进行匹配的时候，返回</span>&lt;/EM&gt;<span style="font-family: 宋体;" lang="ZH-CN">。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">但事实是不会。正则表达式将会匹配&#8220;</span>&lt;EM&gt;first&lt;/EM&gt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。很显然这不是我们想要的结果。原因在于&#8220;</span>+<span style="font-family: 宋体;" lang="ZH-CN">&#8221;是贪婪的。也就是说，&#8220;</span>+<span style="font-family: 宋体;" lang="ZH-CN">&#8221;会导致正则表达式引擎试图尽可能的重复前导字符。只有当这种重复会引起整个正则表达式匹配失败的情况下，引擎会进行回溯。也就是说，它会放弃最后一次的&#8220;重复&#8221;，然后处理正则表达式余下的部分。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">和&#8220;</span>+<span style="font-family: 宋体;" lang="ZH-CN">&#8221;类似，&#8220;</span>?*<span style="font-family: 宋体;" lang="ZH-CN">&#8221;的重复也是贪婪的。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: -0.25in;"><span style="font-family: Symbol;"><span>&#183;<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;" lang="ZH-CN">深入正则表达式引擎内部</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">让我们来看看正则引擎如何匹配前面的例子。第一个记号是&#8220;</span>&lt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，这是一个文字符号。第二个符号是&#8220;</span>.<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，匹配了字符&#8220;</span>E<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，然后&#8220;</span>+<span style="font-family: 宋体;" lang="ZH-CN">&#8221;一直可以匹配其余的字符，直到一行的结束。然后到了换行符，匹配失败</span>(<span style="font-family: 宋体;" lang="ZH-CN">&#8220;</span>.<span style="font-family: 宋体;" lang="ZH-CN">&#8221;不匹配换行符</span>)<span style="font-family: 宋体;" lang="ZH-CN">。于是引擎开始对下一个正则表达式符号进行匹配。也即试图匹配&#8220;</span>&gt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。到目前为止，&#8220;</span>&lt;.+<span style="font-family: 宋体;" lang="ZH-CN">&#8221;已经匹配了&#8220;</span>&lt;EM&gt;first&lt;/EM&gt; test<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。引擎会试图将&#8220;</span>&gt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;与换行符进行匹配，结果失败了。于是引擎进行回溯。结果是现在&#8220;</span>&lt;.+<span style="font-family: 宋体;" lang="ZH-CN">&#8221;匹配&#8220;</span>&lt;EM&gt;first&lt;/EM&gt; tes<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。于是引擎将&#8220;</span>&gt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;与&#8220;</span>t<span style="font-family: 宋体;" lang="ZH-CN">&#8221;进行匹配。显然还是会失败。这个过程继续，直到&#8220;</span>&lt;.+<span style="font-family: 宋体;" lang="ZH-CN">&#8221;匹配&#8220;</span>&lt;EM&gt;first&lt;/EM<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，&#8220;</span>&gt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;与&#8220;</span>&gt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;匹配。于是引擎找到了一个匹配&#8220;</span>&lt;EM&gt;first&lt;/EM&gt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。记住，正则导向的引擎是&#8220;急切的&#8221;，所以它会急着报告它找到的第一个匹配。而不是继续回溯，即使可能会有更好的匹配，例如&#8220;</span>&lt;EM&gt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。所以我们可以看到，由于&#8220;</span>+<span style="font-family: 宋体;" lang="ZH-CN">&#8221;的贪婪性，使得正则表达式引擎返回了一个最左边的最长的匹配。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: 0.3in;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: -0.25in;"><span style="font-family: Symbol;"><span>&#183;<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;" lang="ZH-CN">用懒惰性取代贪婪性</span><o:p></o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">一个用于修正以上问题的可能方案是用&#8220;</span>+<span style="font-family: 宋体;" lang="ZH-CN">&#8221;的惰性代替贪婪性。你可以在&#8220;</span>+<span style="font-family: 宋体;" lang="ZH-CN">&#8221;后面紧跟一个问号&#8220;</span>?<span style="font-family: 宋体;" lang="ZH-CN">&#8221;来达到这一点。&#8220;</span>*<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，&#8220;</span>{}<span style="font-family: 宋体;" lang="ZH-CN">&#8221;和&#8220;</span>?<span style="font-family: 宋体;" lang="ZH-CN">&#8221;表示的重复也可以用这个方案。因此在上面的例子中我们可以使用&#8220;</span>&lt;.+?&gt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。让我们再来看看正则表达式引擎的处理过程。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">再一次，正则表达式记号&#8220;</span>&lt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;会匹配字符串的第一个&#8220;</span>&lt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。下一个正则记号是&#8220;</span>.<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。这次是一个懒惰的&#8220;</span>+<span style="font-family: 宋体;" lang="ZH-CN">&#8221;来重复上一个字符。这告诉正则引擎，尽可能少的重复上一个字符。因此引擎匹配&#8220;</span>.<span style="font-family: 宋体;" lang="ZH-CN">&#8221;和字符&#8220;</span>E<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，然后用&#8220;</span>&gt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;匹配&#8220;</span>M<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，结果失败了。引擎会进行回溯，和上一个例子不同，因为是惰性重复，所以引擎是扩展惰性重复而不是减少，于是&#8220;</span>&lt;.+<span style="font-family: 宋体;" lang="ZH-CN">&#8221;现在被扩展为&#8220;</span>&lt;EM<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。引擎继续匹配下一个记号&#8220;</span>&gt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。这次得到了一个成功匹配。引擎于是报告&#8220;</span>&lt;EM&gt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;是一个成功的匹配。整个过程大致如此。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: 0.3in;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: -0.25in;"><span style="font-family: Symbol;"><span>&#183;<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;" lang="ZH-CN">惰性扩展的一个替代方案</span><o:p></o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">我们还有一个更好的替代方案。可以用一个贪婪重复与一个取反字符集：&#8220;</span>&lt;[^&gt;]+&gt;<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。之所以说这是一个更好的方案在于使用惰性重复时，引擎会在找到一个成功匹配前对每一个字符进行回溯。而使用取反字符集则不需要进行回溯。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">最后要记住的是，本教程仅仅谈到的是正则导向的引擎。文本导向的引擎是不回溯的。但是同时他们也不支持惰性重复操作。</span><o:p></o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.25in; text-indent: -0.25in;"><strong><span><span>7.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span style="font-family: 宋体;" lang="ZH-CN">使用&#8220;</span>.</strong><strong><span style="font-family: 宋体;" lang="ZH-CN">&#8221;匹配几乎任意字符</span><o:p></o:p></strong></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">在正则表达式中，&#8220;</span>.<span style="font-family: 宋体;" lang="ZH-CN">&#8221;是最常用的符号之一。不幸的是，它也是最容易被误用的符号之一。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">&#8220;</span>.<span style="font-family: 宋体;" lang="ZH-CN">&#8221;匹配一个单个的字符而不用关心被匹配的字符是什么。唯一的例外是新行符。在本教程中谈到的引擎，缺省情况下都是不匹配新行符的。因此在缺省情况下，&#8220;</span>.<span style="font-family: 宋体;" lang="ZH-CN">&#8221;等于是字符集</span>[^\n\r](Window)<span style="font-family: 宋体;" lang="ZH-CN">或</span>[^\n]( Unix)<span style="font-family: 宋体;" lang="ZH-CN">的简写。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">这个例外是因为历史的原因。因为早期使用正则表达式的工具是基于行的。它们都是一行一行的读入一个文件，将正则表达式分别应用到每一行上去。在这些工具中，字符串是不包含新行符的。因此&#8220;</span>.<span style="font-family: 宋体;" lang="ZH-CN">&#8221;也就从不匹配新行符。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">现代的工具和语言能够将正则表达式应用到很大的字符串甚至整个文件上去。本教程讨论的所有正则表达式实现都提供一个选项，可以使&#8220;</span>.<span style="font-family: 宋体;" lang="ZH-CN">&#8221;匹配所有的字符，包括新行符。在</span>RegexBuddy, EditPad Pro<span style="font-family: 宋体;" lang="ZH-CN">或</span>PowerGREP<span style="font-family: 宋体;" lang="ZH-CN">等工具中，你可以简单的选中&#8220;点号匹配新行符&#8221;。在</span>Perl<span style="font-family: 宋体;" lang="ZH-CN">中，&#8220;</span>.<span style="font-family: 宋体;" lang="ZH-CN">&#8221;可以匹配新行符的模式被称作&#8220;单行模式&#8221;。很不幸，这是一个很容易混淆的名词。因为还有所谓&#8220;多行模式&#8221;。多行模式只影响行首行尾的锚定</span>(anchor)<span style="font-family: 宋体;" lang="ZH-CN">，而单行模式只影响&#8220;</span>.<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">其他语言和正则表达式库也采用了</span>Perl<span style="font-family: 宋体;" lang="ZH-CN">的术语定义。当在</span>.NET Framework<span style="font-family: 宋体;" lang="ZH-CN">中使用正则表达式类时，你可以用类似下面的语句来激活单行模式：</span>Regex.Match(&#8220;string&#8221;,&#8221;regex&#8221;,RegexOptions.SingleLine)</p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: -0.25in;"><span style="font-family: Symbol;"><span>&#183;<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;" lang="ZH-CN">保守的使用点号&#8220;</span>.<span style="font-family: 宋体;" lang="ZH-CN">&#8221;</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">点号可以说是最强大的元字符。它允许你偷懒：用一个点号，就能匹配几乎所有的字符。但是问题在于，它也常常会匹配不该匹配的字符。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">我会以一个简单的例子来说明。让我们看看如何匹配一个具有&#8220;</span>mm/dd/yy<span style="font-family: 宋体;" lang="ZH-CN">&#8221;格式的日期，但是我们想允许用户来选择分隔符。很快能想到的一个方案是</span>&lt;&lt;\d\d.\d\d.\d\d&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">。看上去它能匹配日期&#8220;</span>02/12/03<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。问题在于</span>02512703<span style="font-family: 宋体;" lang="ZH-CN">也会被认为是一个有效的日期。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;">&lt;&lt;\d\d[-/.]\d\d[-/.]\d\d&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">看上去是一个好一点的解决方案。记住点号在一个字符集里不是元字符。这个方案远不够完善，它会匹配&#8220;</span>99/99/99<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。而</span>&lt;&lt;[0-1]\d[-/.][0-3]\d[-/.]\d\d&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">又更进一步。尽管他也会匹配&#8220;</span>19/39/99<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。你想要你的正则表达式达到如何完美的程度取决于你想达到什么样的目的。如果你想校验用户输入，则需要尽可能的完美。如果你只是想分析一个已知的源，并且我们知道没有错误的数据，用一个比较好的正则表达式来匹配你想要搜寻的字符就已经足够。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><strong><o:p>&nbsp;</o:p></strong></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.25in; text-indent: -0.25in;"><strong><span><span>8.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span style="font-family: 宋体;" lang="ZH-CN">字符串开始和结束的锚定</span><o:p></o:p></strong></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">锚定和一般的正则表达式符号不同，它不匹配任何字符。相反，他们匹配的是字符之前或之后的位置。&#8220;</span>^<span style="font-family: 宋体;" lang="ZH-CN">&#8221;匹配一行字符串第一个字符前的位置。</span>&lt;&lt;^a&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">将会匹配字符串&#8220;</span>abc<span style="font-family: 宋体;" lang="ZH-CN">&#8221;中的</span>a<span style="font-family: 宋体;" lang="ZH-CN">。</span>&lt;&lt;^b&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">将不会匹配&#8220;</span>abc<span style="font-family: 宋体;" lang="ZH-CN">&#8221;中的任何字符。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><span style="font-family: 宋体;" lang="ZH-CN">类似的，</span>$<span style="font-family: 宋体;" lang="ZH-CN">匹配字符串中最后一个字符的后面的位置。所以</span>&lt;&lt;c$&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">匹配&#8220;</span>abc<span style="font-family: 宋体;" lang="ZH-CN">&#8221;中的</span>c<span style="font-family: 宋体;" lang="ZH-CN">。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.25in;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: -0.25in;"><span style="font-family: Symbol;"><span>&#183;<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;" lang="ZH-CN">锚定的应用</span><o:p></o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">在编程语言中校验用户输入时，使用锚定是非常重要的。如果你想校验用户的输入为整数，用</span>&lt;&lt;^\d+$&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">用户输入中，常常会有多余的前导空格或结束空格。你可以用</span>&lt;&lt;^\s*&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">和</span>&lt;&lt;\s*$&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">来匹配前导空格或结束空格。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: -0.25in;"><span style="font-family: Symbol;"><span>&#183;<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;" lang="ZH-CN">使用&#8220;</span>^<span style="font-family: 宋体;" lang="ZH-CN">&#8221;和&#8220;</span>$<span style="font-family: 宋体;" lang="ZH-CN">&#8221;作为行的开始和结束锚定</span><o:p></o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">如果你有一个包含了多行的字符串。例如：&#8220;</span>first line\n\rsecond line<span style="font-family: 宋体;" lang="ZH-CN">&#8221;</span>(<span style="font-family: 宋体;" lang="ZH-CN">其中</span>\n\r<span style="font-family: 宋体;" lang="ZH-CN">表示一个新行符</span>)<span style="font-family: 宋体;" lang="ZH-CN">。常常需要对每行分别处理而不是整个字符串。因此，几乎所有的正则表达式引擎都提供一个选项，可以扩展这两种锚定的含义。&#8220;</span>^<span style="font-family: 宋体;" lang="ZH-CN">&#8221;可以匹配字串的开始位置</span>(<span style="font-family: 宋体;" lang="ZH-CN">在</span>f<span style="font-family: 宋体;" lang="ZH-CN">之前</span>)<span style="font-family: 宋体;" lang="ZH-CN">，以及每一个新行符的后面位置</span>(<span style="font-family: 宋体;" lang="ZH-CN">在</span>\n\r<span style="font-family: 宋体;" lang="ZH-CN">和</span>s<span style="font-family: 宋体;" lang="ZH-CN">之间</span>)<span style="font-family: 宋体;" lang="ZH-CN">。类似的，</span>$<span style="font-family: 宋体;" lang="ZH-CN">会匹配字串的结束位置</span>(<span style="font-family: 宋体;" lang="ZH-CN">最后一个</span>e<span style="font-family: 宋体;" lang="ZH-CN">之后</span>)<span style="font-family: 宋体;" lang="ZH-CN">，以及每个新行符的前面</span>(<span style="font-family: 宋体;" lang="ZH-CN">在</span>e<span style="font-family: 宋体;" lang="ZH-CN">与</span>\n\r<span style="font-family: 宋体;" lang="ZH-CN">之间</span>)<span style="font-family: 宋体;" lang="ZH-CN">。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">在</span>.NET<span style="font-family: 宋体;" lang="ZH-CN">中，当你使用如下代码时，将会定义锚定匹配每一个新行符的前面和后面位置：</span>Regex.Match("string", "regex", RegexOptions.Multiline)</p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">应用：</span>string str = Regex.Replace(Original, "^", "&gt; ", RegexOptions.Multiline)--<span style="font-family: 宋体;" lang="ZH-CN">将会在每行的行首插入&#8220;</span>&gt; <span style="font-family: 宋体;" lang="ZH-CN">&#8221;。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><o:p>&nbsp;</o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt 0.3in; text-indent: -0.25in;"><span style="font-family: Symbol;"><span>&#183;<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体;" lang="ZH-CN">绝对锚定</span><o:p></o:p></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;">&lt;&lt;\A&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">只匹配整个字符串的开始位置，</span>&lt;&lt;\Z&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">只匹配整个字符串的结束位置。即使你使用了&#8220;多行模式&#8221;，</span>&lt;&lt;\A&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">和</span>&lt;&lt;\Z&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">也从不匹配新行符。</span></p>
<p class="msonormal" style="margin: 0in 0in 0pt; text-indent: 0.3in;"><span style="font-family: 宋体;" lang="ZH-CN">即使</span>\Z<span style="font-family: 宋体;" lang="ZH-CN">和</span>$<span style="font-family: 宋体;" lang="ZH-CN">只匹配字符串的结束位置，仍然有一个例外的情况。如果字符串以新行符结束，则</span>\Z<span style="font-family: 宋体;" lang="ZH-CN">和</span>$<span style="font-family: 宋体;" lang="ZH-CN">将会匹配新行符前面的位置，而不是整个字符串的最后面。这个&#8220;改进&#8221;是由</span>Perl<span style="font-family: 宋体;" lang="ZH-CN">引进的，然后被许多的正则表达式实现所遵循，包括</span>Java<span style="font-family: 宋体;" lang="ZH-CN">，</span>.NET<span style="font-family: 宋体;" lang="ZH-CN">等。如果应用</span>&lt;&lt;^[a-z]+$&gt;&gt;<span style="font-family: 宋体;" lang="ZH-CN">到&#8220;</span>joe\n<span style="font-family: 宋体;" lang="ZH-CN">&#8221;，则匹配结果是&#8220;</span>joe<span style="font-family: 宋体;" lang="ZH-CN">&#8221;而不是&#8220;</span>joe\n<span style="font-family: 宋体;" lang="ZH-CN">&#8221;。</span></p>
</div>
<div class="show_page_author" align="right"><br></div><img src ="http://www.cppblog.com/yindmm/aggbug/89484.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yindmm/" target="_blank">yindmm</a> 2009-07-07 19:46 <a href="http://www.cppblog.com/yindmm/archive/2009/07/07/89484.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>百废待兴..</title><link>http://www.cppblog.com/yindmm/archive/2009/07/07/89461.html</link><dc:creator>yindmm</dc:creator><author>yindmm</author><pubDate>Tue, 07 Jul 2009 07:48:00 GMT</pubDate><guid>http://www.cppblog.com/yindmm/archive/2009/07/07/89461.html</guid><wfw:comment>http://www.cppblog.com/yindmm/comments/89461.html</wfw:comment><comments>http://www.cppblog.com/yindmm/archive/2009/07/07/89461.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yindmm/comments/commentRss/89461.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yindmm/services/trackbacks/89461.html</trackback:ping><description><![CDATA[<div style="font-family: 方正舒体;" src_cetemp="/images/cppblog_com/yindmm/12296960128.jpg" align="center"><wbr><br><span style="font-size: 18pt;">I'm back....Everything&nbsp;will be changed....<br></span><br><img alt="" src="http://www.cppblog.com/images/cppblog_com/yindmm/90da0050a2f3b50242a75bd8.jpg" border="0" height="590" width="451"><br><br><span style="font-family: Comic Sans MS;"><font style="font-size: 14pt;" face="方正舒体">负长弓，射天狼，壮志凌云少年郎..<br>千山遥，万水长，神州大地谁能挡..<br>再相逢，游天苍，笑傲山河，两心如一，神仙亦不当...</font><br><br></span></div><img src ="http://www.cppblog.com/yindmm/aggbug/89461.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yindmm/" target="_blank">yindmm</a> 2009-07-07 15:48 <a href="http://www.cppblog.com/yindmm/archive/2009/07/07/89461.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>