﻿<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>盛飞在线 &#187; 正则表达式</title>
	<atom:link href="http://www.senfe.com/archives/tag/%e6%ad%a3%e5%88%99%e8%a1%a8%e8%be%be%e5%bc%8f/feed" rel="self" type="application/rss+xml" />
	<link>http://www.senfe.com</link>
	<description>淡泊以明志，宁静而致远。</description>
	<lastBuildDate>Sat, 28 Jan 2012 13:40:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>正则表达式修饰符</title>
		<link>http://www.senfe.com/archives/423.html</link>
		<comments>http://www.senfe.com/archives/423.html#comments</comments>
		<pubDate>Thu, 13 Aug 2009 00:01:32 +0000</pubDate>
		<dc:creator>盛飞</dc:creator>
				<category><![CDATA[织网]]></category>
		<category><![CDATA[修饰符]]></category>
		<category><![CDATA[正则表达式]]></category>

		<guid isPermaLink="false">http://www.senfe.com/?p=423</guid>
		<description><![CDATA[手册是没有,这些都是修饰符 i ：如果在修饰符中加上”i”，则正则将会取消大小写敏感性，即”a”和”A” 是一样的。 m：默认的正则开始”^”和结束”$”只是对于正则字符串如果在修饰符中加上”m”，那么开始和结束将会指字符串的每一行：每一行的开头就是”^”，结尾就是”$”。 s：如果在修饰符中加入”s”，那么默认的”.”代表除了换行符以外的任何字符将会变成任意字符，也就是包括换行符！ x：如果加上该修饰符，表达式中的空白字符将会被忽略，除非它已经被转义。 e：本修饰符仅仅对于replacement有用，代表在replacement中作为PHP代码。 A：如果使用这个修饰符，那么表达式必须是匹配的字符串中的开头部分。比如说”/a/A”匹配”abcd”。 E：与”m”相反，如果使用这个修饰符，那么”$”将匹配绝对字符串的结尾，而不是换行符前面，默认就打开了这个模式。 U：和问号的作用差不多，用于设置”贪婪模式”。 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;- 模式修正符 模式修正符 &#8212; 解说正则表达式模式中使用的修正符 说明 下面列出了当前在 PCRE 中可能使用的修正符。括号中是这些修正符的内部 PCRE 名。修正符中的空格和换行被忽略，其它字符会导致错误。 i (PCRE_CASELESS) 如果设定此修正符，模式中的字符将同时匹配大小写字母。 m（PCRE_MULTILINE） 默认情况下，PCRE 将目标字符串作为单一的一“行”字符所组成的（甚至其中包含有换行符也是如此）。“行起始”元字符（^）仅仅匹配字符串的起始，“行结束”元字符（$）仅仅匹配字符串的结束，或者最后一个字符是换行符时其前面（除非设定了 D 修正符）。这和 Perl 是一样的。 当设定了此修正符，“行起始”和“行结束”除了匹配整个字符串开头和结束外，还分别匹配其中的换行符的之后和之前。这和 Perl 的 /m 修正符是等效的。如果目标字符串中没有“\n”字符或者模式中没有 ^ 或 $，则设定此修正符没有任何效果。 s（PCRE_DOTALL） 如果设定了此修正符，模式中的圆点元字符（.）匹配所有的字符，包括换行符。没有此设定的话，则不包括换行符。这和 Perl 的 /s 修正符是等效的。排除字符类例如 [^a] 总是匹配换行符的，无论是否设定了此修正符。 x（PCRE_EXTENDED） 如果设定了此修正符，模式中的空白字符除了被转义的或在字符类中的以外完全被忽略，在未转义的字符类之外的 # 以及下一个换行符之间的所有字符，包括两头，也都被忽略。这和 Perl 的 /x [...]]]></description>
			<content:encoded><![CDATA[<p>手册是没有,这些都是修饰符<br />
i ：如果在修饰符中加上”i”，则正则将会取消大小写敏感性，即”a”和”A” 是一样的。<br />
m：默认的正则开始”^”和结束”$”只是对于正则字符串如果在修饰符中加上”m”，那么开始和结束将会指字符串的每一行：每一行的开头就是”^”，结尾就是”$”。<br />
s：如果在修饰符中加入”s”，那么默认的”.”代表除了换行符以外的任何字符将会变成任意字符，也就是包括换行符！<br />
x：如果加上该修饰符，表达式中的空白字符将会被忽略，除非它已经被转义。<br />
e：本修饰符仅仅对于replacement有用，代表在replacement中作为PHP代码。<br />
A：如果使用这个修饰符，那么表达式必须是匹配的字符串中的开头部分。比如说”/a/A”匹配”abcd”。<br />
E：与”m”相反，如果使用这个修饰符，那么”$”将匹配绝对字符串的结尾，而不是换行符前面，默认就打开了这个模式。<br />
U：和问号的作用差不多，用于设置”贪婪模式”。<br />
<span id="more-423"></span><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>模式修正符<br />
模式修正符 &#8212; 解说正则表达式模式中使用的修正符<br />
说明<br />
下面列出了当前在 PCRE 中可能使用的修正符。括号中是这些修正符的内部 PCRE 名。修正符中的空格和换行被忽略，其它字符会导致错误。</p>
<p>i (PCRE_CASELESS)<br />
如果设定此修正符，模式中的字符将同时匹配大小写字母。</p>
<p>m（PCRE_MULTILINE）<br />
默认情况下，PCRE 将目标字符串作为单一的一“行”字符所组成的（甚至其中包含有换行符也是如此）。“行起始”元字符（^）仅仅匹配字符串的起始，“行结束”元字符（$）仅仅匹配字符串的结束，或者最后一个字符是换行符时其前面（除非设定了 D 修正符）。这和 Perl 是一样的。</p>
<p>当设定了此修正符，“行起始”和“行结束”除了匹配整个字符串开头和结束外，还分别匹配其中的换行符的之后和之前。这和 Perl 的 /m 修正符是等效的。如果目标字符串中没有“\n”字符或者模式中没有 ^ 或 $，则设定此修正符没有任何效果。</p>
<p>s（PCRE_DOTALL）<br />
如果设定了此修正符，模式中的圆点元字符（.）匹配所有的字符，包括换行符。没有此设定的话，则不包括换行符。这和 Perl 的 /s 修正符是等效的。排除字符类例如 [^a] 总是匹配换行符的，无论是否设定了此修正符。</p>
<p>x（PCRE_EXTENDED）<br />
如果设定了此修正符，模式中的空白字符除了被转义的或在字符类中的以外完全被忽略，在未转义的字符类之外的 # 以及下一个换行符之间的所有字符，包括两头，也都被忽略。这和 Perl 的 /x 修正符是等效的，使得可以在复杂的模式中加入注释。然而注意，这仅适用于数据字符。空白字符可能永远不会出现于模式中的特殊字符序列，例如引入条件子模式的序列 (?( 中间。</p>
<p>e<br />
如果设定了此修正符，preg_replace() 在替换字符串中对逆向引用作正常的替换，将其作为 PHP 代码求值，并用其结果来替换所搜索的字符串。</p>
<p>只有 preg_replace() 使用此修正符，其它 PCRE 函数将忽略之。</p>
<p>注: 本修正符在 PHP3 中不可用。</p>
<p>A（PCRE_ANCHORED）<br />
如果设定了此修正符，模式被强制为“anchored”，即强制仅从目标字符串的开头开始匹配。此效果也可以通过适当的模式本身来实现（在 Perl 中实现的唯一方法）。</p>
<p>D（PCRE_DOLLAR_ENDONLY）<br />
如果设定了此修正符，模式中的美元元字符仅匹配目标字符串的结尾。没有此选项时，如果最后一个字符是换行符的话，美元符号也会匹配此字符之前（但不会匹配任何其它换行符之前）。如果设定了 m 修正符则忽略此选项。Perl 中没有与其等价的修正符。</p>
<p>S<br />
当一个模式将被使用若干次时，为加速匹配起见值得先对其进行分析。如果设定了此修正符则会进行额外的分析。目前，分析一个模式仅对没有单一固定起始字符的 non-anchored 模式有用。</p>
<p>U（PCRE_UNGREEDY）<br />
本修正符反转了匹配数量的值使其不是默认的重复，而变成在后面跟上“?”才变得重复。这和 Perl 不兼容。也可以通过在模式之中设定 (?U) 修正符或者在数量符之后跟一个问号（如 .*?）来启用此选项。</p>
<p>X（PCRE_EXTRA）<br />
此修正符启用了一个 PCRE 中与 Perl 不兼容的额外功能。模式中的任何反斜线后面跟上一个没有特殊意义的字母导致一个错误，从而保留此组合以备将来扩充。默认情况下，和 Perl 一样，一个反斜线后面跟一个没有特殊意义的字母被当成该字母本身。当前没有其它特性受此修正符控制。</p>
<p>u（PCRE_UTF8）<br />
此修正符启用了一个 PCRE 中与 Perl 不兼容的额外功能。模式字符串被当成 UTF-8。本修正符在 Unix 下自 PHP 4.1.0 起可用，在 win32 下自 PHP 4.2.3 起可用。自 PHP 4.3.5 起开始检查模式的 UTF-8 合法性。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.senfe.com/archives/423.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>正则表达式高级技巧基本概念实例详解[译]</title>
		<link>http://www.senfe.com/archives/337.html</link>
		<comments>http://www.senfe.com/archives/337.html#comments</comments>
		<pubDate>Thu, 04 Jun 2009 21:31:23 +0000</pubDate>
		<dc:creator>盛飞</dc:creator>
				<category><![CDATA[织网]]></category>
		<category><![CDATA[基本概念]]></category>
		<category><![CDATA[实例]]></category>
		<category><![CDATA[正则]]></category>
		<category><![CDATA[正则表达式]]></category>
		<category><![CDATA[高级技巧]]></category>

		<guid isPermaLink="false">http://www.senfe.com/?p=337</guid>
		<description><![CDATA[英文原文来自Smashing Magazine。由笨活儿翻译。转载请注明出处。 正则表达式(Regular Expression, abbr. regex) 功能强大，能够用于在一大串字符里找到所需信息。它利用约定俗成的字符结构表达式来发生作用。不幸的是，简单的正则表达式对于一些高级运用，功能远远不够。若要进行筛选的结构比较复杂，你可能就需要用到高级正则表达式。 本文为您介绍正则表达式的高级技巧。我们筛选出了八个常用的概念，并配上实例解析，每个例子都是满足某种复杂要求的简单写法。如果你对正则的基本概念尚缺乏了解，请先阅读这篇文章，或者这个教程，或者维基条目。 这里的正则语法适用于PHP，与Perl兼容。 1. 贪婪/懒惰 所有能多次限定的正则运算符都是贪婪的。他们尽可能多地匹配目标字符串，也就是说匹配结果会尽可能地长。不幸的是，这种做法并不总是我们想要的。因此，我们添加“懒惰”限定符来解决问题。在各个贪婪运算符后添加“?”能让表达式只匹配尽可能短的长度。另外，修改器“U”也能惰化能多次限定的运算符。理解贪婪与懒惰的区别是运用高级正则表达式的基础。 贪婪操作符 操作符 * 匹配之前的表达式零次或零次以上。它是一个贪婪操作符。请看下面的例子： 1 2 preg_match&#40; '/&#60;h1&#62;.*&#60;\/h1&#62;/', '&#60;h1&#62;这是一个标题。&#60;/h1&#62; &#60;h1&#62;这是另一个。&#60;/h1&#62;', $matches &#41;; 句点(.)能代表除换行符外的任意字符。上面的正则表达式匹配 h1 标签以及标签内的所有内容。它用句点(.)和星号(*)来匹配标签内的所有内容。匹配结果如下： 1 &#60;h1&#62;这是一个标题。&#60;/h1&#62;&#60;h1&#62;这是另一个。&#60;/h1&#62; 整个字串都被返回。* 操作符会连续匹配所有内容—— 甚至包括中间的 h1 闭合标签。因为它是贪婪的，匹配整个字串是符合其利益最大化原则。 懒惰操作符 把上面的式子稍作修改，加上一个问号(?)，能让表达式变懒惰： 1 /&#60;h1&#62;.*?&#60;\/h1&#62;/ 这样它会觉得，只需匹配到第一个 h1 结尾标签就完成任务了。 另一个有着类似属性的贪婪操作符是 {n,} 。它代表之前的匹配模式重复n次或n次以上，如果没有加上问号，它会寻找尽可能多的重复次数，加上的话，则会尽可能少重复（当然也就是“重复n次”最少）。 1 2 3 4 5 6 # 建立字串 $str = 'hihihi [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>英文原文来自<a title="Smashing Magazine" href="http://www.smashingmagazine.com/2009/05/06/introduction-to-advanced-regular-expressions/" target="_blank">Smashing Magazine</a>。由<a title="正则表达式高级技巧" href="http://blog.benhuoer.com/posts/crucial-concepts-behind-advanced-regular-expressions.html" target="_blank">笨活儿</a>翻译。转载请注明出处。</p>
</blockquote>
<p>正则表达式(Regular Expression,  <em>abbr. regex</em>) 功能强大，能够用于在一大串字符里找到所需信息。它利用约定俗成的字符结构表达式来发生作用。不幸的是，简单的正则表达式对于一些高级运用，功能远远不够。若要进行筛选的结构比较复杂，你可能就需要用到<strong>高级正则表达式</strong>。</p>
<p>本文为您<strong>介绍正则表达式的高级技巧</strong>。我们筛选出了八个常用的概念，并配上实例解析，每个例子都是满足某种复杂要求的简单写法。如果你对正则的基本概念尚缺乏了解，请先阅读<a title="正则表达式入门" href="http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#introduction" target="_blank">这篇文章</a>，或者<a href="http://www.regexlab.com/zh/deelx/syntax.htm" target="_blank">这个教程</a>，或者<a title="维基百科" href="http://zh.wikipedia.org/wiki/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F" target="_blank">维基条目</a>。</p>
<p>这里的正则语法适用于PHP，与<a title="维基百科" href="http://zh.wikipedia.org/wiki/Perl" target="_blank">Perl</a>兼容。</p>
<p><span id="more-971"></span></p>
<h3>1. 贪婪/懒惰</h3>
<p><img src="http://www.senfe.com/wp-content/uploads/2009/06/551a_greed.jpg" alt="Greed" width="400" height="300" /></p>
<p>所有能多次限定的正则运算符都是贪婪的。他们<strong>尽可能多</strong>地匹配目标字符串，也就是说匹配结果会<strong>尽可能地长</strong>。不幸的是，这种做法并不总是我们想要的。因此，我们添加“懒惰”限定符来解决问题。在各个贪婪运算符后添加“?”能让表达式只匹配<strong>尽可能短</strong>的长度。另外，修改器“U”也能惰化能多次限定的运算符。理解贪婪与懒惰的区别是运用高级正则表达式的基础。</p>
<h4>贪婪操作符</h4>
<p>操作符 * 匹配之前的表达式零次或零次以上。它是一个贪婪操作符。请看下面的例子：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'/&lt;h1&gt;.*&lt;\/h1&gt;/'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'&lt;h1&gt;这是一个标题。&lt;/h1&gt;
&lt;h1&gt;这是另一个。&lt;/h1&gt;'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>句点(.)能代表除换行符外的任意字符。上面的正则表达式匹配 h1 标签以及标签内的所有内容。它用句点(.)和星号(*)来匹配标签内的所有内容。匹配结果如下：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">&lt;</span>h1<span style="color: #339933;">&gt;</span>这是一个标题。<span style="color: #339933;">&lt;/</span>h1<span style="color: #339933;">&gt;&lt;</span>h1<span style="color: #339933;">&gt;</span>这是另一个。<span style="color: #339933;">&lt;/</span>h1<span style="color: #339933;">&gt;</span></pre></td></tr></table></div>

<p>整个字串都被返回。* 操作符会连续匹配所有内容—— 甚至包括中间的 h1 闭合标签。因为它是贪婪的，匹配整个字串是符合其利益最大化原则。</p>
<h4>懒惰操作符</h4>
<p>把上面的式子稍作修改，加上一个问号(?)，能让表达式变懒惰：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">/&lt;</span>h1<span style="color: #339933;">&gt;.*</span>?<span style="color: #339933;">&lt;</span>\<span style="color: #339933;">/</span>h1<span style="color: #339933;">&gt;/</span></pre></td></tr></table></div>

<p>这样它会觉得，只需匹配到第一个 h1 结尾标签就完成任务了。</p>
<p>另一个有着类似属性的贪婪操作符是 {n,} 。它代表之前的匹配模式重复n次或n次以上，如果没有加上问号，它会寻找尽可能多的重复次数，加上的话，则会尽可能少重复（当然也就是“重复n次”最少）。</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># 建立字串
</span><span style="color: #000088;">$str</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'hihihi oops hi'</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;"># 使用贪婪的{n,}操作符进行匹配
</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'/(hi){2,}/'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$str</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>  <span style="color: #666666; font-style: italic;"># matches[0] 将是 'hihihi'
</span><span style="color: #666666; font-style: italic;"># 使用堕化了的 {n,}? 操作符匹配
</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'/(hi){2,}?/'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$str</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>  <span style="color: #666666; font-style: italic;"># matches[0] 将是 'hihi'</span></pre></td></tr></table></div>

<p><span id="more-337"></span></p>
<h3>2. 回返引用(Back referencing)</h3>
<p><img src="http://www.senfe.com/wp-content/uploads/2009/06/1e54_back.jpg" alt="Back Referencing" width="300" height="290" /></p>
<h4>有什么用？</h4>
<p><strong>回返引用(Back referencing)</strong>一般被翻译成“反向引用”、“后向引用”、“向后引用”，个人觉得“回返引用”更为贴切[<a title="笨活儿" href="http://blog.benhuoer.com/">笨活儿</a>]。它是在正则表达式内部引用<strong>之前捕获到的内容</strong>的方法。例如，下面这个简单例子的目的是匹配出引号内部的内容：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># 建立匹配数组
</span><span style="color: #000088;">$matches</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># 建立字串
</span><span style="color: #000088;">$str</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\&quot;</span>This is a 'string'<span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># 用正则表达式捕捉内容
</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;/(<span style="color: #000099; font-weight: bold;">\&quot;</span>|').*?(<span style="color: #000099; font-weight: bold;">\&quot;</span>|')/&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$str</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># 输出整个匹配字串
</span><span style="color: #b1b100;">echo</span>  <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>它会输出：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #0000ff;">&quot;This is a'</span></pre></td></tr></table></div>

<p>显然，这并不是我们想要的内容。</p>
<p>这个表达式从开头的双引号开始匹配，遭遇单引号之后就错误地结束了匹配。这是因为表达式里说：(“|&#8217;)，也就是双引号（”）和单引号（&#8217;）均可。要修正这个问题，你可以用到回返引用。<strong>表达式\1,\2,&#8230;,\9</strong> 是对前面已捕获到的各个子内容的编组序号，能作为对这些编组的“指针”而被引用。在此例中，第一个被匹配的引号就由1代表。</p>
<h4>如何运用？</h4>
<p>将上面的例子中，后面的闭合引号替换为1：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'/(&quot;|\').*?\1/'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$str</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>这会正确地返回字串：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #0000ff;">&quot;This is a 'string'&quot;</span></pre></td></tr></table></div>

<blockquote><p><strong>译注思考题：</strong></p>
<p>如果是中文引号，前引号和后引号不是同一个字符，怎么办？</p>
</blockquote>
<p>还记得PHP函数 preg_replace 吗？其中也有回返引用。只不过我们没有用 \1 … \9，而是用了 $1 … $9 … $n （此处任意数目均可）作为回返指针。例如，如果你想把所有的段落标签
<p>都替换成文本：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$text</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'/&lt;p&gt;(.*?)&lt;\/p&gt;/'</span><span style="color: #339933;">,</span>
<span style="color: #0000ff;">'&amp;lt;p&amp;gt;$1&amp;lt;/p&amp;gt;'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$html</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>参数$1是一个回返引用，代表段落标签
<p>内部的文字，并插入到替换后的文本里。这种简便易用的表达式写法为我们提供了一个获取已匹配文字的简单方法，甚至在替换文本时也能使用。</p>
<h3>3. 已命名捕获组(Named Groups)</h3>
<p>当在一个表达式内多次用到回调引用时，很容易就把事情搞混淆，要弄清那些数字（\1 … \9）都代表哪一个子内容是件很麻烦的事。回调引用的一个替代方法是使用带名字的捕获组（下文简称“有名组”）。有名组使用(?P<name>pattern)来设定，name代表组名，pattern是配合该有名组的正则结构。请看下面的例子：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">/</span><span style="color: #009900;">&#40;</span>?P<span style="color: #339933;">&lt;</span>quote<span style="color: #339933;">&gt;</span><span style="color: #0000ff;">&quot;|').*?(?P=quote)/</span></pre></td></tr></table></div>

<p>上式中，quote就是组名，”|&#8217;是改组匹配内容的正则。后面的(?P=quote)是在调用组名为quote的有名组。这个式子的效果和上面的回调引用实例一样，只不过是用了有名组来实现。是不是更加易读易懂了？</p>
<p>有名组也能用于处理已匹配内容之数组的内部数据。赋予特定正则的组名也能作为所匹配到的内容在数组内部的索引词。</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'/(?P&lt;quote&gt;&quot;|\')/'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;'String'&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># 下面的语句输出“'”(不包括双引号)
</span><span style="color: #b1b100;">echo</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># 使用组名调用，也会输出“'”
</span><span style="color: #b1b100;">echo</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'quote'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>所以，有名组并不只是让写代码更容易，它也能用于组织代码。</p>
<h3>4. 字词边界(Word Boundaries)</h3>
<p><img src="http://www.senfe.com/wp-content/uploads/2009/06/25dd_boundary.jpg" alt="Word Boundaries" width="400" height="284" /></p>
<p><strong>字词边界</strong>是字串里的字词字符（包括字母、数字和下划线，自然也包括汉字）和非字词字符之间的位置。其特殊之处就在于，它并不匹配某个实在的字符。它的长度是<strong>零</strong>。 \b 匹配所有字词边界。</p>
<p>不幸的是，字词边界一般都被忽视掉了，大部分人都没有在意他的现实意义。 例如，如果你想要匹配单词“import”：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">/</span>import<span style="color: #339933;">/</span></pre></td></tr></table></div>

<p>注意了！正则表达式有时候很调皮的。下面的字串也能和上面的式子匹配成功：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;">important</pre></td></tr></table></div>

<p>你或许觉得，只要在import前后加上空格，不就可以匹配这个独立的单词了：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">/</span> import <span style="color: #339933;">/</span></pre></td></tr></table></div>

<p>那如果遇上这种情况呢：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;">The trader voted <span style="color: #b1b100;">for</span> the import</pre></td></tr></table></div>

<p>当 import 这个词在字串开头或者结尾时，修改后的表达式仍然不能用。因此，考虑各种情况是必须的：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">/</span><span style="color: #009900;">&#40;</span>^import <span style="color: #339933;">|</span> import <span style="color: #339933;">|</span> import$<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span>i</pre></td></tr></table></div>

<p>别慌，还没完呢。如果遇到标点符号了呢？就为了满足这一个单词的匹配，你的正则可能就需要这样写：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">/</span><span style="color: #009900;">&#40;</span>^import<span style="color: #009900;">&#40;</span><span style="color: #339933;">:|;|,</span><span style="color: #009900;">&#41;</span>? <span style="color: #339933;">|</span> import<span style="color: #009900;">&#40;</span><span style="color: #339933;">:|;|,</span><span style="color: #009900;">&#41;</span>? <span style="color: #339933;">|</span> import<span style="color: #009900;">&#40;</span>\<span style="color: #339933;">.|</span>\?<span style="color: #339933;">|!</span><span style="color: #009900;">&#41;</span>?$<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span>i</pre></td></tr></table></div>

<p>对于只匹配一个单词来说，这样做实在是有点大动干戈了。正因如此，字词边界才显得意义重大。要适应上述要求，以及<strong>很多其他情况变种</strong>，有了字符边界，我们所需写的代码只是：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">/</span>\bimport\b<span style="color: #339933;">/</span></pre></td></tr></table></div>

<p>上面所有情况都得到了解决。\ b 的灵活性就在于，它是一个没有长度的匹配。它只匹配两个实际字符之间想象出的位置。它检查两个相邻字符是否是一个为单字，另一个为非单字。情况符合，就返回匹配。如果遇到了单词的开头或结尾， \b 会把它当成是非单词字符对待。由于import里面的 i 仍然被看成是单词字符，import 就被匹配出来了。</p>
<p>注意，与\b相对，我们还有\B，此操作符匹配两个单字或者两个非单字之间的位置。因此，如果你想匹配在某个单词内部的‘hi’，可以使用：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;">\Bhi\B</pre></td></tr></table></div>

<p>“this”、“hight”，都会返回匹配，而“hi there”则不会返回匹配。</p>
<h3>5. 最小组团(Atomic Groups)</h3>
<p><img src="http://www.senfe.com/wp-content/uploads/2009/06/f104_groups.jpg" alt="Advanced Operators" width="400" height="266" /></p>
<p><strong>最小组团</strong>是无捕捉的特殊正则表达式分组。通常用来提高正则表达式的效能，也能用于消除特定匹配。一个最小组团可以用(?>pattern) 来定义，其中pattern是匹配式。</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">/</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">?&gt;</span>his<span style="color: #339933;">|</span>this<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span></pre></td></tr></table></div>

<p>当正则引擎针对最小组团进行匹配时，它会跳过组团内标记的回溯位置。以单词“smashing”为例，当用上面的正则表达式匹配时，正则引擎会先尝试在“smashing”里寻找“his”。显然，找不到任何匹配。此时，最小组团就发挥作用了：正则引擎会放弃所有回溯位置。也就是说，它不会尝试再从“smashing”里查找“this”。为什么要这样设置？因为“his”都没有返回匹配结果，包含有“his”的“this”当然就更匹配不了了！</p>
<p>上面的例子并没有什么实用性，我们用/t?his?/ 也能达到效果。再看看下面的例子：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">/</span>\b<span style="color: #009900;">&#40;</span>engineer<span style="color: #339933;">|</span>engrave<span style="color: #339933;">|</span>end<span style="color: #009900;">&#41;</span>\b<span style="color: #339933;">/</span></pre></td></tr></table></div>

<p>如果把“engineering”拿去匹配，正则引擎会先匹配到“engineer”，但接下来就遇到了字词边界，\b，所以匹配不成功。然后，正则引擎又会尝试在字串里寻找下一个匹配内容：engrave。匹配到eng的时候，后面的又对不上了，匹配失败。最后，尝试“end”，结果同样是失败。仔细观察，你会发现，一旦engineer匹配失败，并且都抵达了字词边界，“engrave”和“end”这两个词就已经不可能匹配成功了。这两个词都比engineer短小，正则引擎不应该再多做无谓的尝试。</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">/</span>\b<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">?&gt;</span>engineer<span style="color: #339933;">|</span>engrave<span style="color: #339933;">|</span>end<span style="color: #009900;">&#41;</span>\b<span style="color: #339933;">/</span></pre></td></tr></table></div>

<p>上面的替代写法更能节省正则引擎的匹配时间，提高代码的工作效率。</p>
<h3>6. 递归(Recursion)</h3>
<p><img src="http://www.senfe.com/wp-content/uploads/2009/06/8dd6_recursion.jpg" alt="Recursion" width="400" height="300" /></p>
<p><strong>递归(Recursion)</strong>用于匹配嵌套结构，例如括弧嵌套， (this (that))，HTML标签嵌套
<div>
<div></div>
</div>
<p>。我们使用(?R)来代表递归过程中的子模式。下面是一个匹配嵌套括弧的例子：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">/</span>\<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">?&gt;</span><span style="color: #009900;">&#91;</span>^<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">|</span><span style="color: #009900;">&#40;</span>?R<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span>\<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span></pre></td></tr></table></div>

<p>最外层使用了反义符的括号“(”匹配嵌套结构的开端。然后是一个多选项操作符( * | * )，可能匹配除括号外的所有字符 “(?>[^()]+)”，也可能是通过子模式“(?R)”来再次匹配整个表达式。请注意，这个操作符会尽量多地匹配所有嵌套。</p>
<p>递归的另一个实例如下：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">/&lt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#91;</span>\w<span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.*</span><span style="color: #000000; font-weight: bold;">?&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">?&gt;</span><span style="color: #009900;">&#91;</span>^<span style="color: #339933;">&lt;&gt;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">|</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>?R<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">*&lt;</span>\<span style="color: #339933;">/</span>\<span style="color: #cc66cc;">1</span><span style="color: #339933;">&gt;/</span></pre></td></tr></table></div>

<p>以上表达式综合运用了字符分组，贪婪操作符、回溯，以及最小化组团来匹配嵌套标签。第一个括弧内分组([\w]+)匹配出标签名，用于接下来的应用。若找到这尖括号样式的标签，则尝试寻找标签内容的剩余部分。下一个括弧括起来的子表达式和上一个实例非常相似：要么匹配不包括尖括号的所有字符 ?>[^<>]+，要么递归匹配整个表达式(?R)。表达式最后的<\/1>代表闭合标签。</p>
<h3>7. 回调(Callbacks)</h3>
<p><img src="http://www.senfe.com/wp-content/uploads/2009/06/d7fd_call.jpg" alt="Callbacks" width="400" height="290" /></p>
<p>匹配结果中的特定内容有时可能会需要某种特别的修改。要应用多重而复杂的修改，正则表达式<strong>的回调</strong>就有了用武之地。回调是用于函数preg_replace_callback中的动态修改字串的方式。你可以为preg_replace_callback指定某个函数为参数，此函数能接收匹配结果数组为参数，并将数组修改后返回，作为替换的结果。</p>
<p>例如，我们想将某字串中的字母全部转变成大写。十分不巧，PHP没有直接转化字母大小写的正则操作符。要完成这项任务，就可以用到正则回调。首先，表达式要匹配出所有需要被大写的字母：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">/</span>\b\w<span style="color: #339933;">/</span></pre></td></tr></table></div>

<p>上式同时使用了字词边界和字符类。光有这个式子还不够，我们还需要一个回调函数：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> upper_case<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$matches</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<span style="color: #b1b100;">return</span> <span style="color: #990000;">strtoupper</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>函数upper_case接收匹配结果数组，并将整个匹配结果转化成大写。 在此例中，$matches[0]代表需要被大写化的字母。然后，我们再利用preg_replace_callback实现回调：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #990000;">preg_replace_callback</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'/\b\w/'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'upper_case'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$str</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>一个简单的回调即有这般强大的力量。</p>
<h3>8. 注释(Commenting)</h3>
<p><img src="http://www.senfe.com/wp-content/uploads/2009/06/1035_comment.jpg" alt="Commenting" width="400" height="300" /></p>
<p><strong>注释</strong>不用来匹配字串，但确实是正则表达式中最重要的部分。当正则越写越深入，越写越复杂，要推译出究竟什么东西被匹配就会变得越来越困难。在正则表达式中间加上注释，是最小化将来的迷糊和困惑的最佳方式。</p>
<p>要在正则表达式内部加上注释，使用(?#comment)格式。把“comment”替换成你的注释语句：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">/</span><span style="color: #009900;">&#40;</span>?<span style="color: #666666; font-style: italic;">#数字)\d/</span></pre></td></tr></table></div>

<p>如果你打算把代码公之于众，为正则表达式加上注释就显得尤为重要。这样别人才能更容易看懂和修改你的代码。和其他场合的注释一样，这样做也能为你重访自己以前写的程序时提供方便。</p>
<p>考虑使用“x”或“(?x)”修改器来格式化注释。这个修改器让正则引擎忽略表达式参数之间的空格。“有用的”空格仍然能够通过[ ]或\s，或者\ （反义符加空格）来匹配。</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">/</span>
\d    <span style="color: #666666; font-style: italic;">#digit
</span><span style="color: #009900;">&#91;</span> <span style="color: #009900;">&#93;</span>   <span style="color: #666666; font-style: italic;">#space
</span>\w<span style="color: #339933;">+</span>   <span style="color: #666666; font-style: italic;">#word
</span><span style="color: #339933;">/</span>x</pre></td></tr></table></div>

<p>上面的代码与下面的式子作用一样：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">/</span>\d<span style="color: #009900;">&#40;</span>?<span style="color: #666666; font-style: italic;">#digit)[ ](?#space)\w+(?#word)/</span></pre></td></tr></table></div>

<p>请时刻注意代码的可读性。</p>
<h3>更多资源（英文）</h3>
<ul>
<li><a href="http://www.regular-expressions.info/" target="_blank">Regular-Expressions.info</a> Comprehensive website on regular expressions</li>
<li><a href="http://www.addedbytes.com/cheat-sheets/regular-expressions-cheat-sheet/" target="_blank"> Cheat Sheet</a>Informative regular expressions cheat sheet</li>
<li><a href="http://www.jslab.dk/tools.regex.php" target="_blank"> Regex Generator</a>JavaScript regular expressions generator</li>
</ul>
<h4>关于作者</h4>
<p><em>Karthik Viswanathan 是一个喜欢编程和做网站的高中生。你可以到他的博客上查看他的作品：<a href="http://www.lateralcode.com/" target="_blank">Lateral Code</a>。你也可以关注一下他的线上<a href="http://twitter.lateralcode.com/" target="_blank">Twitter应用</a>。</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.senfe.com/archives/337.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

