<?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; lookaround</title>
	<atom:link href="http://iregex.org/blog/tag/lookaround/feed" rel="self" type="application/rss+xml" />
	<link>http://iregex.org</link>
	<description>原创、翻译、转载关于正则表达式的文章</description>
	<lastBuildDate>Tue, 29 Mar 2011 05:04:10 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com"/><atom:link rel="hub" href="http://superfeedr.com/hubbub"/><atom:link rel="hub" href="http://www.feedsky.com/api/RPC2"/><atom:link rel="hub" href="http://blogsearch.google.com/ping/RPC2"/><atom:link rel="hub" href="http://blog.yodao.com/ping/RPC2"/><atom:link rel="hub" href="http://www.feedsky.com/api/RPC2"/><atom:link rel="hub" href="http://www.xianguo.com/xmlrpc/ping.php"/><atom:link rel="hub" href="http://www.zhuaxia.com/rpc/server.php"/><atom:link rel="hub" href="http://rpc.technorati.com/rpc/ping"/><atom:link rel="hub" href="http://rpc.pingomatic.com/"/>		<item>
		<title>小议“排除型匹配”</title>
		<link>http://iregex.org/blog/negate-match.html</link>
		<comments>http://iregex.org/blog/negate-match.html#comments</comments>
		<pubDate>Mon, 24 May 2010 08:46:29 +0000</pubDate>
		<dc:creator>rex</dc:creator>
				<category><![CDATA[教程]]></category>
		<category><![CDATA[问答]]></category>
		<category><![CDATA[exclude]]></category>
		<category><![CDATA[lookaround]]></category>
		<category><![CDATA[negate]]></category>
		<category><![CDATA[perl]]></category>

		<guid isPermaLink="false">http://iregex.org/?p=122</guid>
		<description><![CDATA[网友cfc4n问及关于(?!)的正则表达式问题。回答之后，顺便总结了一下Perl语言中如何匹配“不出现”某元素，贴在这里。 问题 问题描述 有如下文本，如何使用正则式，将其中不含color选项的item... ]]></description>
			<content:encoded><![CDATA[<p>网友cfc4n问及关于(?!)的正则表达式问题。回答之后，顺便总结了一下Perl语言中如何匹配“不出现”某元素，贴在这里。<span id="more-122"></span></p>
<h2 style="background-color: rgb(153, 204, 0); border: 1px solid rgb(102, 102, 102); color: rgb(0, 0, 0); font-size: 21px; line-height: 35px; padding-top: 3px; text-indent: 6px;">问题</h2>
<blockquote style="border-left:2px solid #DDDDDD; margin:15px 30px 0 10px; padding-left:20px;">
<h3 style="color: #127ADB; font-size:14px; padding-bottom:3px; padding-top:3px; margin:1.5em 0 1em;">问题描述</h3>
<blockquote style="border-left:2px solid #DDDDDD; margin:15px 30px 0 10px; padding-left:20px;"><p>
    有如下文本，如何使用正则式，将其中<b>不含color选项的item</b>匹配出来？</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;item&gt;<br />
&nbsp; &nbsp; color:red;<br />
&lt;/item&gt;<br />
&lt;item&gt;<br />
&nbsp; &nbsp; size:12;<br />
&nbsp; &nbsp; number:45;<br />
&nbsp; &nbsp; type:good;<br />
&lt;/item&gt;</div></td></tr></tbody></table></div>
</blockquote>
<h3 style="color: #127ADB; font-size:14px; padding-bottom:3px; padding-top:3px; margin:1.5em 0 1em;">典型的错误答案</h3>
<blockquote style="border-left:2px solid #DDDDDD; margin:15px 30px 0 10px; padding-left:20px;">
<p>新手容易提供这样的错误答案：<code class="codecolorer perl default"><span class="perl"><span style="color: #009999;">&lt;item&gt;</span><span style="color: #339933;">.*?</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">?!</span>color<span style="color: #009900;">&#41;</span><span style="color: #339933;">.*?&lt;/</span>item<span style="color: #339933;">&gt;</span></span></code>。其出发点是正确的：只有当color不出现在目标字串时，该匹配才是所需要的。事实上，这样的正则表达式不能如君所愿，它匹配所有的<code class="codecolorer text default"><span class="text">&lt;item&gt;...&lt;/item&gt;</span></code>。这是为什么呢？</p>
</blockquote>
</blockquote>
<h2 style="background-color: rgb(153, 204, 0); border: 1px solid rgb(102, 102, 102); color: rgb(0, 0, 0); font-size: 21px; line-height: 35px; padding-top: 3px; text-indent: 6px;">Perl之排除型匹配</h2>
<blockquote style="border-left:2px solid #DDDDDD; margin:15px 30px 0 10px; padding-left:20px;">
<h3 style="color: #127ADB; font-size:14px; padding-bottom:3px; padding-top:3px; margin:1.5em 0 1em;">最简单的排除型匹配</h3>
<blockquote style="border-left:2px solid #DDDDDD; margin:15px 30px 0 10px; padding-left:20px;">
<p>匹配是<code class="codecolorer perl default"><span class="perl"><span style="color: #339933;">=~</span></span></code>, 不匹配当然是 <code class="codecolorer perl default"><span class="perl"><span style="color: #339933;">!~</span></span></code> 了。写到这里想到，在正则式中，凡是由<code class="codecolorer perl default"><span class="perl"><span style="color: #339933;">=</span></span></code>组成的正则式符号，全可以使用<code class="codecolorer perl default"><span class="perl"><span style="color: #339933;">!</span></span></code>来替代，以表现相反的意思。例如<code class="codecolorer perl default"><span class="perl"><span style="color: #009900;">&#40;</span><span style="color: #339933;">?=</span><span style="color: #009900;">&#41;</span></span></code>与<code class="codecolorer perl default"><span class="perl"><span style="color: #009900;">&#40;</span><span style="color: #339933;">?!</span><span style="color: #009900;">&#41;</span></span></code>，<code class="codecolorer perl default"><span class="perl"><span style="color: #009900;">&#40;</span><span style="color: #339933;">?&lt;=</span><span style="color: #009900;">&#41;</span></span></code>与<code class="codecolorer perl default"><span class="perl"><span style="color: #009900;">&#40;</span><span style="color: #339933;">?&lt;!</span><span style="color: #009900;">&#41;</span></span></code>，<code class="codecolorer perl default"><span class="perl"><span style="color: #339933;">=~</span></span></code>与<code class="codecolorer perl default"><span class="perl"><span style="color: #339933;">!~</span></span></code>。</p>
<p>返回正题，看个例子。如果要检测某字串是否含有good，当然要用<code class="codecolorer perl default"><span class="perl"><span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$string</span> <span style="color: #339933;">=~</span> <span style="color: #009966; font-style: italic;">/good/</span><span style="color: #009900;">&#41;</span></span></code>，如果<code class="codecolorer perl default"><span class="perl"><span style="color: #0000ff;">$string</span></span></code>里有good则条件为真，否则为假；</p>
<p>如果要检测某字串是否<b>不</b>含有good，可以用<code class="codecolorer perl default"><span class="perl"><span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$string</span> <span style="color: #339933;">!~</span> <span style="color: #009966; font-style: italic;">/good/</span><span style="color: #009900;">&#41;</span></span></code>，如果<code class="codecolorer perl default"><span class="perl"><span style="color: #0000ff;">$string</span></span></code>里没有good则条件为真，否则为假。</p>
<p>这种匹配测试，较适合于在大段的字串中搜索某个简单的模式，然后对于匹配的结果作出两种不同的判断，非此即彼。虽然迅速干练，但是对于复杂情况的判断，还是有些累赘。</p>
<p>对于文章开始提出的问题而言，当然可以这样解决：先搜索所有的 <code class="codecolorer text default"><span class="text">&lt;item&gt;...&lt;/item&gt;</span></code>，然后分别判断是否存在color项即可：</p>
<div class="codecolorer-container perl mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td><div class="perl codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">#!/usr/bin/perl -w</span><br />
<br />
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$text</span><span style="color: #339933;">=</span><span style="color: #cc0000; font-style: italic;">&lt;&lt;END;<br />
&lt;item&gt;<br />
&nbsp; &nbsp; color:red;<br />
&lt;/item&gt;<br />
&lt;item&gt;<br />
&nbsp; &nbsp; size:12;<br />
&nbsp; &nbsp; number:45;<br />
&nbsp; &nbsp; type:good;<br />
&lt;/item&gt;<br />
END</span><br />
<br />
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@result</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$text</span><span style="color: #339933;">=~</span> <span style="color: #000066;">m</span><span style="color: #339933;">!</span><span style="color: #009999;">&lt;item&gt;</span><span style="color: #339933;">.*?&lt;/</span>item<span style="color: #339933;">&gt;!</span>sg<span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">foreach</span> <span style="color: #0000ff;">$item</span> <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">@result</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$item</span> <span style="color: #339933;">!~</span> <span style="color: #009966; font-style: italic;">/color/</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066;">print</span> <span style="color: #ff0000;">&quot;$item&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>输出结果是:</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;item&gt;<br />
&nbsp; &nbsp; size:12;<br />
&nbsp; &nbsp; number:45;<br />
&nbsp; &nbsp; type:good;<br />
&lt;/item&gt;</div></td></tr></tbody></table></div>
<p>虽然也不错，但是它总是“宁可错杀不可错放”地找完所有可能项，再一一重新进行排除。能否一开始就先界定，我们要找的是<strong>不含color的item</strong>呢？<span style="color:#ff008c">排除型匹配</span>正是为此而生。</p>
</blockquote>
<h3 style="color: #127ADB; font-size:14px; padding-bottom:3px; padding-top:3px; margin:1.5em 0 1em;">排除型匹配</h3>
<blockquote style="border-left:2px solid #DDDDDD; margin:15px 30px 0 10px; padding-left:20px;">
<p>不好意思，“排除型匹配”这个词是我生造的。其它的说法或许是“否定断言”，“否定环视”等等。后两者的命名，都是从匹配过程的角度出发；而此处命名，是从结果出发。具体说来，就是使用 <code class="codecolorer perl default"><span class="perl"><span style="color: #009900;">&#40;</span><span style="color: #339933;">?!...</span><span style="color: #009900;">&#41;</span></span></code>和<code class="codecolorer perl default"><span class="perl"><span style="color: #009900;">&#40;</span><span style="color: #339933;">?&lt;!...</span><span style="color: #009900;">&#41;</span></span></code>作为辅助条件判断，来简化正则表达式，方便快捷地找到符合要求的匹配。</p>
<p>这两个东东的使用方法类似，都是指，当前位置<span style="color:#ff008c">不出现</span>某种模式。不同的是，<code class="codecolorer perl default"><span class="perl"><span style="color: #009900;">&#40;</span><span style="color: #339933;">?!...</span><span style="color: #009900;">&#41;</span></span></code>是指当前位置的右边，而<code class="codecolorer perl default"><span class="perl"><span style="color: #009900;">&#40;</span><span style="color: #339933;">?&lt;!</span><span style="color: #009900;">&#41;</span></span></code>自然就是指左边了。</p>
<p>这里隆重推出<a href="http://anrs.sacredfir.com/" target="_blank" title="我爱正则表达式">Anrs</a>同学翻译的教程: <a href="http://anrs.sacredfir.com/archives/295" target="_blank" title="我爱正则表达式">环视一</a>以及<a href="http://anrs.sacredfir.com/archives/338" target="_blank" title="我爱正则表达式">环视二</a>。仔细阅读这两文章，彻底明白环视这两个概念，将会提升您的正则表达式功力。后文将建立在您已经理解环视这个概念的基础上。</p>
<p>闲话一句。既然使用“左边”和“右边”既形象又好懂，为什么没见过“左瞻”，“右瞻”，“左向”，“右向”，反而全是些“前瞻后瞻”，“正向逆向”这样的不好理解的说法呢？<a href="https://twitter.com/kwl_01_skz/status/14069944812" target="_blank" title="我爱正则表达式">撕烤者</a>也同有此问。我的理解是，或许是为了照顾阿语等从右向左书写的用户的习惯吧。无论如何，将从 <code class="codecolorer perl default"><span class="perl"><span style="color: #339933;">^</span></span></code>到 <code class="codecolorer perl default"><span class="perl">$</span></code>的方向称之为“向前”总不会错。</p>
<p>描述当前位置（左侧或右侧）的模式，从而辅助判断正则式是否匹配，是环视的作用。它只描述，不消耗字符；只辅助判断，从不单独出现。这与<code class="codecolorer perl default"><span class="perl"><span style="color: #339933;">^</span></span></code>和<code class="codecolorer perl default"><span class="perl">$</span></code>简直如出一辙。</p>
</blockquote>
<h3 style="color: #127ADB; font-size:14px; padding-bottom:3px; padding-top:3px; margin:1.5em 0 1em;">一则例子</h3>
<blockquote style="border-left:2px solid #DDDDDD; margin:15px 30px 0 10px; padding-left:20px;">
<p><strong>例子. </strong>现在有许多与fanfou.com类似的网址。如何写一条正则表达式，来匹配域名含fanfou，但是TLS不是.com的模式？</p>
<p><strong>答案：</strong><code class="codecolorer perl default"><span class="perl"><span style="color: #339933;">/</span><span style="color: #0000ff;">\bfanfou</span>\<span style="color: #339933;">.</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">?!</span>com<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span>a<span style="color: #339933;">-</span>z<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#123;</span><span style="color: #cc66cc;">2</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">4</span><span style="color: #009900;">&#125;</span><span style="color: #0000ff;">\b</span><span style="color: #339933;">/</span>i</span></code>。分析这条正则表达式：</p>
<blockquote style="border-left:2px solid #DDDDDD; margin:15px 30px 0 10px; padding-left:20px;">
<ul>
<li>以<code class="codecolorer perl default"><span class="perl"><span style="color: #0000ff;">\b</span></span></code>开始，明确字符边界；</li>
<li>fanfou主域名不可少；</li>
<li><code class="codecolorer perl default"><span class="perl">\<span style="color: #339933;">.</span></span></code>匹配一个普通的点号；此处不要使用点号元字符；</li>
<li><code class="codecolorer perl default"><span class="perl"><span style="color: #009900;">&#40;</span><span style="color: #339933;">?!</span>com<span style="color: #009900;">&#41;</span></span></code>表示此处（即从<code class="codecolorer text default"><span class="text">fanfou.</span></code>的右边）不得出现com三个连续字符；</li>
<li><code class="codecolorer perl default"><span class="perl"><span style="color: #009900;">&#91;</span>a<span style="color: #339933;">-</span>z<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#123;</span><span style="color: #cc66cc;">2</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">4</span><span style="color: #009900;">&#125;</span></span></code>表示是2至4位的拉丁字母；因为域名的TLS最短是2位（如.au, .us），最长可为4位（如.info, .asia）；</li>
<li>右侧边界同样重要，否则我们之前的{2,4}就白费了；</li>
<li>使用i表示不分大小写；这是域名的特征之一。</li>
</ul>
</blockquote>
</blockquote>
<h3 style="color: #127ADB; font-size:14px; padding-bottom:3px; padding-top:3px; margin:1.5em 0 1em;">回到本题</h3>
<blockquote style="border-left:2px solid #DDDDDD; margin:15px 30px 0 10px; padding-left:20px;"><p>
        按照要求，一步步建立这条正则式。</p>
<blockquote style="border-left:2px solid #DDDDDD; margin:15px 30px 0 10px; padding-left:20px;">
<ul>
<li>该正则式匹配的是<code class="codecolorer text default"><span class="text">&lt;item&gt;...&lt;/item&gt;</span></code>结构。因此，正则式以<code class="codecolorer perl default"><span class="perl"><span style="color: #009999;">&lt;item&gt;</span></span></code>开始。</li>
<li>在<code class="codecolorer text default"><span class="text">&lt;item&gt;</span></code>和<code class="codecolorer text default"><span class="text">&lt;/item&gt;</span></code>之间不得出现color，是这条正则式的难点。因为，<code class="codecolorer text default"><span class="text">color</span></code>可能位于这个结构之内的任意一点，因此要规定，此内任意一点都不得出现color一词。这样的点为：<code class="codecolorer perl default"><span class="perl"><span style="color: #009900;">&#40;</span><span style="color: #339933;">?!</span>color<span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span></span></code>。这样的点重复1+次，正则式写为<code class="codecolorer perl default"><span class="perl"><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">?!</span>color<span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span></span></code>。注意这里有个小陷阱：不要写为<code class="codecolorer perl default"><span class="perl"><span style="color: #009900;">&#40;</span><span style="color: #339933;">?!</span>color<span style="color: #009900;">&#41;</span><span style="color: #339933;">.+</span></span></code>，否则它只描述了最左侧的一点不得出现color，其余部分则都无所谓。而写为<code class="codecolorer perl default"><span class="perl"><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">?!</span>color<span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span></span></code>则保证每一点都不出现color。</li>
<li>正则式此时为<code class="codecolorer perl default"><span class="perl"><span style="color: #009999;">&lt;item&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">?!</span>color<span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+?&lt;/</span>item<span style="color: #339933;">&gt;</span></span></code>。为了节省资源，括号通常写成非捕获模式<code class="codecolorer perl default"><span class="perl"><span style="color: #009900;">&#40;</span><span style="color: #339933;">?:...</span><span style="color: #009900;">&#41;</span></span></code>；为了保证点号匹配换行符，可以指定s模式或使用<code class="codecolorer perl default"><span class="perl"><span style="color: #009900;">&#91;</span>\<span style="color: #000066;">s</span><span style="color: #0000ff;">\S</span><span style="color: #009900;">&#93;</span></span></code>代替点号元字符。此处仍使用点号。正则式修改为<code class="codecolorer perl default"><span class="perl"><span style="color: #009999;">&lt;item&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">?:</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">?!</span>color<span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+?&lt;/</span>item<span style="color: #339933;">&gt;</span></span></code>。</li>
</ul>
</blockquote>
</blockquote>
</blockquote>
<p>总体来说，环视相对于基本的元字符还是要抽象一些。不过一旦理解并掌握了它，就会发现它在精确匹配和替换时十分有用。上面的分析，希望有所帮助。如果您有类似的问题，欢迎提出。</p>
]]></content:encoded>
			<wfw:commentRss>http://iregex.org/blog/negate-match.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>两条与密码验证相关的正则表达式问题</title>
		<link>http://iregex.org/blog/2-regex-problems-about-password-verification.html</link>
		<comments>http://iregex.org/blog/2-regex-problems-about-password-verification.html#comments</comments>
		<pubDate>Fri, 16 Oct 2009 14:38:39 +0000</pubDate>
		<dc:creator>rex</dc:creator>
				<category><![CDATA[问答]]></category>
		<category><![CDATA[lookaround]]></category>
		<category><![CDATA[密码验证]]></category>
		<category><![CDATA[环视]]></category>

		<guid isPermaLink="false">http://iregex.org/?p=68</guid>
		<description><![CDATA[在正则表达式论坛上，有人问了这样两个问题（原贴在这里）： 问题1: 密码验证：由且仅由数字、字母（大小写）、特殊符号（@ % &#38;&#8230;）组成，三者缺一不可，密码不少于8位。 问题2: 十... ]]></description>
			<content:encoded><![CDATA[<p>在<a target="_blank" href="http://regex.me/" title="正则表达式论坛">正则表达式论坛</a>上，有人问了这样两个问题（原贴在<a target="_blank" href="http://regex.me/thread-149-page-1.html" title="正则表达式论坛">这里</a>）：</p>
<div align="left">
<blockquote style="border-left:2px solid #DDDDDD; margin:15px 30px 0 10px; padding-left:20px;">
<ul>
<li><b>问题1</b>: 密码验证：由且仅由数字、字母（大小写）、特殊符号（@ % &amp;&#8230;）组成，三者缺一不可，密码不少于8位。</li>
<li><b>问题2</b>: 十位的数字、字母组合密码，其中包含4位数字和6位字母。</li>
</ul>
</blockquote>
<p>感兴趣的话，建议您在读下文之前，自己思考一下解法，以免被我的思路干扰。</p>
</div>
<h2 style="background-color:#99CC00; font-size:14px; padding-bottom:3px; padding-left:10px; padding-top:3px;  line-height:1.5em; margin:1.5em 0 1em;">Stage0<br />
</h2>
<div align="left">这两个问题其实都是一个路子：对于一段字符串，有多个并列的限定条件。</p>
<p>对于问题1，它需要满足的条件如下：</p>
<ul>
<li>8位以上；</li>
<li>必须包含1位以上的数字；</li>
<li>必须包含1位以上的字母；</li>
<li>必须包含1位以上的特殊字符。</li>
</ul>
<p>对于这样的要求，简单使用[0-9a-za-Z@%&amp;]{8,}来匹配的。因此它也匹配像00000000、1111aaaaa这样只含一种或两种字符的字符串。因此，我们要加上更为严格的限制条件，以便匹配更精确。</p>
</div>
<h2 style="background-color:#99CC00; font-size:14px; padding-bottom:3px; padding-left:10px; padding-top:3px;  line-height:1.5em; margin:1.5em 0 1em;">Stage1</h2>
<div align="left">
数字必须出现一次，则对于每个字符位置来说，它应该是这样的：</p>
<p>代码:</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[0-9a-zA-Z@%&amp;amp;]+\d</div></td></tr></tbody></table></div>
<p>字母必须出现一次，则对于每个字符位置来说，它应该是这样的：</p>
<p>代码:</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[0-9a-zA-Z@%&amp;amp;]+[a-zA-Z]</div></td></tr></tbody></table></div>
<p>特殊字符必须出现一次，则对于每个字符位置来说，它应该是这样的：</p>
<p>代码:</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[0-9a-zA-Z@%&amp;amp;]+[@%&amp;amp;]</div></td></tr></tbody></table></div>
<p>这三个条件必须同时满足，因此：<br />
代码:</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">(?=[0-9a-zA-Z@%&amp;amp;]+\d)(?=[0-9a-zA-Z@%&amp;amp;]+[a-zA-Z])(?=[0-9a-zA-Z@%&amp;amp;]+[@%&amp;amp;]).{8,}</div></td></tr></tbody></table></div>
<p>为了保证字符整行匹配，需要加上条件^$：<br />
代码:</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">^(?=[0-9a-zA-Z@%&amp;amp;]+\d)(?=[0-9a-zA-Z@%&amp;amp;]+[a-zA-Z])(?=[0-9a-zA-Z@%&amp;amp;]+[@%&amp;amp;]).{8,}$</div></td></tr></tbody></table></div>
<p>它匹配的是，8位(包括)以上字符，由且仅由数字、字母和特殊字符组成。</p>
</div>
<h2 style="background-color:#99CC00; font-size:14px; padding-bottom:3px; padding-left:10px; padding-top:3px;  line-height:1.5em; margin:1.5em 0 1em;">Stage2</h2>
<div align="left">
stage1 中的解法，已经可以匹配所需要的结果了。但是，与stage0 代码[0-9a-za-Z@%&amp;]{8,}相反，它只能匹配部分合乎条件的字串，同时会漏掉另一外一些情况。看图：</p>
<p><a href="http://i293.photobucket.com/albums/mm60/zhasm/iregex/20091016104924_half.png" target="_blank" title="我爱正则表达式|两条与密码验证相关的正则表达式问题"><img src="http://i293.photobucket.com/albums/mm60/zhasm/iregex/20091016104924_half.png" alt="我爱正则表达式|两条与密码验证相关的正则表达式问题" border="0" /></a></p>
<p>上图中Test部分中彩色部分为正则表达所匹配的字串。但是前三条是符合要求的，却不被匹配。之所以会出现这样的情况，是因为在环视条件中使用了<font color="#ff008c">+量词</font>，这会将本来用作辅助验证的字符被消耗掉，原本合格的字串被误认为不合格了。</p>
<p>问题出在+上，因此我们使用<font color="#ff008c">*量词</font>，这样就好多了。正则表达式为：</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">^(?=[0-9a-zA-Z@%&amp;amp;]*\d)(?=[0-9a-zA-Z@%&amp;amp;]*[a-zA-Z])(?=[0-9a-zA-Z@%&amp;amp;]*[@%&amp;amp;]).{8,}$</div></td></tr></tbody></table></div>
<p>匹配效果如下所示：</p>
<p><a href="http://i293.photobucket.com/albums/mm60/zhasm/iregex/20091016net.png" target="_blank" title="我爱正则表达式|两条与密码验证相关的正则表达式问题"><img src="http://i293.photobucket.com/albums/mm60/zhasm/iregex/20091016net.png" alt="我爱正则表达式|两条与密码验证相关的正则表达式问题" border="0" /></a></div>
<h2 style="background-color:#99CC00; font-size:14px; padding-bottom:3px; padding-left:10px; padding-top:3px;  line-height:1.5em; margin:1.5em 0 1em;">Stage3</h2>
<p>但是问题依然存在。测试发现，像这样的字串也是匹配的，但是它显然不是合格的密码字串：</p>
<p><a href="http://s293.photobucket.com/albums/mm60/zhasm/iregex/?action=view&amp;current=screenshot_001.png" target="_blank" title="我爱正则表达式|两条与密码验证相关的正则表达式问题"><img src="http://i293.photobucket.com/albums/mm60/zhasm/iregex/screenshot_001.png" alt="Photobucket" border="0" /></a></p>
<p>之所以出现这样的问题，是因为stage2代码中</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">.{8,}$</div></td></tr></tbody></table></div>
<p>前边千辛万苦使用[0-9a-zA-Z@%&amp;]所界定的条件，在这里轻轻松松被破坏了。stage2其实只管前8位，只要前8位字符符合要求，它就认为万事大吉了。</p>
<p>认识到这一点，我写个一条长长的正则式：</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">^(?=[0-9a-zA-Z@%&amp;amp;]*\d)(?=[0-9a-zA-Z@%&amp;amp;]*[a-zA-Z])(?=[0-9a-zA-Z@%&amp;amp;]*[@%&amp;amp;])[0-9a-zA-Z@%&amp;amp;]{8,}$</div></td></tr></tbody></table></div>
<p>但是这条正则表达太复杂了。能不能短一些呢？当然可以。从上文可以看出，前边其实不必界定太复杂的条件，只要在最后加上条件判断即可。因此，正则表达式可以改为：</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">^(?=.*\d)(?=.*[a-zA-Z])(?=.*[@%&amp;amp;])[0-9a-zA-Z@%&amp;amp;]{8,}$</div></td></tr></tbody></table></div>
<p>这样一来，我们就得到了这道题迄今为止最简洁的解法。</p>
<p>同理可得，第二道题的解法是：</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">^(?=.*\d)(?=.*[a-zA-Z])(?=.*[@%&amp;amp;])[0-9a-zA-Z@%&amp;amp;]{8,}$</div></td></tr></tbody></table></div>
<p>不多解释。</p>
<p>在思考本题的过程中，感谢<a target="_blank" href="http://hi.baidu.com/jyf1987">创亿无限</a>在stage2的测试，感谢<a target="_blank" href="http://www.luanxiang.org/blog/">余晟老师</a>在stage3中的指点。余老师现在正写一本正则表达式的傻瓜书，请点击<a target="_blank" href="http://www.luanxiang.org/blog/">余晟老师</a>的博客来探寻详情。</p>
]]></content:encoded>
			<wfw:commentRss>http://iregex.org/blog/2-regex-problems-about-password-verification.html/feed</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
	</channel>
</rss>

