一月 22nd, 2010

CSS透明属性详解

No Comments, 前端开发, by admin.
透明往往能产生不错的网页视觉效果,先奉上兼容主流浏览器的CSS透明代码:

.transparent_class {
filter:alpha(opacity=50);
-moz-opacity:0.5;
-khtml-opacity: 0.5;
opacity: 0.5;
}

上面的几个属性分别是:

  • opacity: 0.5; 这是最重要的,因为它是CSS标准.该属性支持Firefox, Safari和 Opera.
  • filter:alpha(opacity=50); 这个是为IE6设的,可取值在0-100,其它三个0到1.
  • -moz-opacity:0.5; 这个是为了支持一些老版本的Mozilla浏览器。
  • -khtml-opacity: 0.5; 这个为了支持一些老版本的Safari浏览器。

CSS透明度继承问题

但CSS的透明属性涉及到一个继承问题,当为父级元素设置透明度后,子元素将自动继承其透明度,比如本站的一个效果:

即使你又为子元素指定透明度为1也是无效的。

对于子元素是文字的情况,我的解决方法一般是如果多少还能够看清,就不管。另一个折衷的方法是,为文本子元素指定一个相对更深的颜色。也就是说,当子元素继承透明度后,所得到的文本颜色正好就是你想要的。前提是,这个颜色还有加深的可能,和需要详细的计算颜色和透明度的值。

还有“取消透明度继承”的说法,这个说法是不太准确的,据我个人所知,没有任何取消透明度继承的方法。只能说,当想要实现“多个元素覆盖,只让指定的元素透明”时,可以使用的一些Hack。

搜了一下,找到一个不错的实现这种效果的方法 – 一个关于透明继承度的问题,有兴趣的朋友可以看看。原理很简单,添加一个空元素作为透明层,和不想透明但是要实现覆盖效果的元素为同级元素。父级元素使用position:relative定位; 两个子元素使用position:absolute定位,实现覆盖。

一月 22nd, 2010

色彩的含义

No Comments, 前端开发, by admin.

在自然界中有最丰富的色彩资源,比如阳光、花草、天空、大海等,它们自身的颜色已被人们不知不觉地接受、认同并形成一种意识,一种独特的感觉。很 多人对颜色的感觉或联想都是相似的,这种特点叫做“共通性”,这是出于传统习惯的缘故。因此不同的颜色能给观众以沉静、活泼、温暖、寒冷等直接的感受,也 可以形成热烈、冷漠、朴素、典雅、清爽、愉快等感觉。大家习惯以某种颜色表示某种特定的意义,于是该颜色就变成了某事物的象征。颜色的意义在世界上也具有 共通性,但由于民族习惯不同也会存在很大差异。下面首先对一些内涵表达强烈的颜色做一些介绍。

红色,是 火的色彩,也是血的颜色,首先给人的感觉是温暖、兴奋、热烈、坚强和威严,所以我们的国旗使用红色赋予了革命的含意。在西方,据说耶稣的血是葡萄酒色,所 以又表示圣餐和祭奠。粉红色是健康的表示,而深红色则意味着嫉妒或暴力,被认为是恶魔的象征。除此之外,红色也给人以警告、恐怖、危险感,所以应用于交通 信号的停止信号,消防系统的标志色等。

黄色,属于暖色,代表光明、欢悦,色相温柔、平和。在中国过去是帝王的象征色,有高贵、尊严的含义,一般人不得使用。黄色在古罗马也被当作高贵色。东方佛教喜爱雅素、脱俗,常用黄色暗示超然物外的境界,基督教同样作为犹太衣服的颜色;有时黄色也代表娇嫩、幼稚。

绿色是大自然的代表色,象征春天、新鲜、自然和生长,也用来象征和平、安全、无污染,比如我们常说的绿色食品,同时绿色也是未成年人的象征。绿色在西方有另一种含意是嫉妒的恶魔。

蓝色给人幽雅、深刻的感觉,有冷静和无限空间的意味,也表示希望、幸福。在西方,蓝色象征着名门贵族。但蓝色也是绝望凄凉的同义语。在日本,也用蓝色表示青年、青春或者少年等年轻的一代。同时,蓝色也是联合国规定的新闻象征颜色。

紫色也具有高贵庄重的内涵,日本和中国在过去都以服色来表示等级,用紫色是最高级的。至今在某些仪式上仍旧用做紫幕、方绸巾等。在古希腊,紫色作为国王的服装专用色。总之,紫色意味着高贵的世家。

白色
通 常是优美轻快、纯洁、高尚、和平和神圣的代语。自然界中雪是白色的、云是白色的。因此,白色给人以素雅、寒冷的印象;有时也代表脆弱、悲哀之意。不同的民 族对它有不同的好恶。中国和印度以白象和白牛,作为吉祥和神圣的象征。日本的老道与和尚喜欢穿白衣服。西方结婚的新娘穿白色婚纱。相反,中国办丧事却用白 色孝服。

黑色,代 表黑暗和恐怖,意喻死亡、悲哀,属不吉利色。它表示一种深沉、神秘,使人产生凄寒和失望的意念。但把黑和其他颜色相配时却显出黑色的力量和个性,如黑白相 衬,显得精致、新鲜、有活力。在黑色衬托下可以使用各种非常刺激的冷暖颜色,因为它有调和色彩的作用。1.5.2 色彩的对比
通过上面的介绍,相信读者也会联想身边的事物,它们为什么使用这种颜色,以及这种颜色赋予该事物的独特意义。一切颜色不但具有不同的特性,而且各种色彩之 间也产生相关性及相对性。评价一种颜色是浑浊还是新鲜,是明快还是暗淡,是寒冷还是温暖,一定要和其他色彩发生相互关系才能进行判断,单独用一种颜色是无 法评价的。下面我们根据颜色的多种特性进行辩证理解。
首先,从颜色的冷暖开始比较,例如,所有的色彩纯度一样,感觉最强的首先是橙黄,其次是红,再次是黄、绿、紫、青、蓝。红、橙黄属于暖色,紫介于寒暖之 间,习惯上也称之为中间色。其实,中间色也存在某种程度的寒暖差异。绿介于青和黄之间,若偏黄一些则显暖,具有膨胀和发扬的感觉。凡是冷色,都具有沉着和 收缩的感觉。凡是比较浑浊的色彩,在人的视觉上就产生了一种脏的感觉。有浊必有清,凡是比较纯正的色彩一般产生鲜明感。色彩相关性体现在类似和对比这两个 方面,两者都可从颜色的寒暖、明暗、清浊的特性上找到区别。

所有色彩除了本身具有不同冷暖特性之外,还由于黑白含量的多少会造成明色和暗色的差别。因此,每一种色彩都形成各种深浅不同的色调。当两种不同色彩放在一 起进行比较时,首先会产生明暗上的对比效果。而色彩的对比并不局限于上面所述的这些。如果把一种华丽的颜色和朴素的颜色放在一起,把光滑的和粗糙的放在一 起,也将发生不同对比效果。尤其是那些特性不明显的色彩,也可以通过对比的方法,使它们的性格鲜明起来。如果配合得好,鲜艳的颜色不仅不会掩盖另一个晦暗 的颜色,而且,还可以提高它的色彩效果。比如,一种灰颜色,把它放在暖色旁边,它就有些偏冷,如果把它放在冷色旁边,看上去就有些偏暖的感觉。色彩还有一 个特性就是从面积上进行对比。例如,大面积界限分明的色调使一幅画具有力量和生气。在深暗的色调中如以面积较小的亮色调相衬托,会赋予肃穆、庄重的感觉。

色彩的对比效果可以做到很强烈,也可以做到很柔和,但要注意,突出的色彩使用太多会造成注意力的分散,只会破坏构图的统一。在追求某种艺术效果时,往往可 以利用物质材料的本色来产生,以更好地体现自然美。关于“对比美”这个法则可以运用在不同的手法中。为满足主观的要求,应注意材料的制约性与色彩、环境之 间的互相关系。特别应注意色彩与色彩之间、材料与材料之间、环境与主体之间的既相互制约又相互补充的辩证关系。

色彩的构成

构成是将几个单元重新组合成为一个新单元的过程。它是一种与造型有关的概念,也是现代造型设计用语。在这里将介绍色彩构成:色彩构成是指配色方面的平衡、分隔、节奏、强调、协调等方法的使用。

● 平衡

重色和轻色、明色和暗色、强色和弱色、膨胀色和收缩色等都是相对立的色彩,配色时应改变其面积和形状以保持平衡。

不同量的各种颜色,由于比较的结果就会形成均衡或不均衡的感觉。要达到均衡,配备颜色时要考虑到屏幕上、下、左、右以及两个对角关系上的均衡,不要把很强或很弱的颜色孤立在一边。同时,也要注意每种颜色的面积大小变化,这也是均衡的关键。

● 分隔

主画面颜色的面积大小和变化是均衡的关键,分隔也是如此,主要是在配色时,在交界处嵌入别的颜色,从而使原配色分离,以此来补救色彩间因类似而过分弱或因对比而过分强的缺陷。

● 节奏

平衡和分隔也是体现画面节奏的重要因素,节奏是通过色调、明度、纯度的某种变动和往复,以及色彩的协调、对照和照应而产生的,以此来表现出色彩的运动感和空间感。这个节奏取决于形态配置的和谐。为了效果更好,可使色调变化作渐变的效果。

● 强调

强调是通过面积较小的鲜明色改善整体单调的效果,强调是使颜色之间紧密联系并且平衡的关键,应贯穿于整体。比如,在大面积的暖色中加一小块较冷的色彩,或 在一大块亮颜色上放一小块暗的色彩,也可反之,这样可以打破画面的呆板。也就是说我们运用颜色的各种对比方法来达到强调的目的,我们往往使用红和绿、黄和 紫、橙黄和青做对比。

● 协调

协调就是以某颜色为主调,调和色彩,使各色之间统一联系、互相呼应和感觉协调,以此来表现统一的感觉。协调决定了一幅作品的成败,主要指冷暖色和明暗调的统一,整体被哪种色调所支配。可以说有几种不同的主调,就有几种不同的协调效果。

要掌握协调的规律其实很简单,就是记住各种颜色的浓淡、冷暖以及明暗的搭配变化,比如黄与橙、蓝与绿、青与紫、浅绿与深蓝、浅黄与深橙等。

概要:
在jQuery库,几乎所有的jQuery插件都被约束在它的命名空间里,通常,“global”对象同样被存储在jQuery命名空间里,因些不会使它与其它库(如:Prototype, MooTools, or YUI)发生冲突。
注意,jQuery用”$”作为它自身的默认快捷方式。

“$”的功能:
当jQuery与其它库被加载后,你也可以不顾它的默认快捷方式而在任意一处通过调用jQuery.noConflict()函数来指定使用jQuery库,例如:
Java代码
<html>
<head>
<script src=”prototype.js”></script>
<script src=”jquery.js”></script>
<script>
jQuery.noConflict();

// Use jQuery via jQuery(…)
jQuery(document).ready(function(){
jQuery(“div”).hide();
});

// Use Prototype with $(…), etc.
$(’someid’).style.display = ‘none’;
</script>
</head>
<body></body>
</html>

这将使$回到它的原始库里,你依然可以在其它的应用程序里使用”jQuery”。
另外,还有其它选项。如果你想确定jQuery不会与其它库冲突——但你又想自定义一个比较短快捷方式,你可以这么做:
Java代码
<html>
<head>
<script src=”prototype.js”></script>
<script src=”jquery.js”></script>
<script>
var $j = jQuery.noConflict();

// Use jQuery via $j(…)
$j(document).ready(function(){
$j(“div”).hide();
});

// Use Prototype with $(…), etc.
$(’someid’).style.display = ‘none’;
</script>
</head>
<body></body>
</html>

你能够自定义你自己的备用名称(如:jq、$J、awesomequery——可以是任何你想要的)。
如果你不想给jQuery自定义其它备用名称(你更愿意使用$而不管其它库的$方法)而又不想与其它库相冲突时,以下的解决方法最常使用的。
Java代码
<html>
<head>
<script src=”prototype.js”></script>
<script src=”jquery.js”></script>
<script>
jQuery.noConflict();

// Put all your code in your document ready area
jQuery(document).ready(function($){
// Do jQuery stuff using $
$(“div”).hide();
});

// Use Prototype with $(…), etc.
$(’someid’).style.display = ‘none’;
</script>
</head>
<body></body>
</html>

对于你的大部分代码而言,这或许是最理想的方式,因为你可以以改变最少的代码来实现完全的兼容性。

参考:适合jQuery的快捷表示方式
如果你不喜欢总是键入完整的”jQuery”,有一些可供替换的快捷方式:
重新指定jQuery为其它快捷方式
Java代码
var $j = jQuery;

如果你想使用其它不同的库,这或许是最好的方法。
使用下列方法,可以指定在一块代码内使用”$”:
Java代码
function($) { // some code that uses $ })(jQuery)

备注:如果你使用了这种方法,在这块代码中你将不能使用”$”来调用Prototype方法,因为你选择了在这块代码中唯一使用jQuery方法。
使用以下方法来实现DOM ready event:
Java代码
jQuery(function($) { // some code that uses $ });

备注:同样,在这个代码块里你也还有调用Prototype方法。

1, FF下给 div 设置 padding 后会导致 width 和 height 增加(DIV的实际宽度=DIV宽+Padding), 但IE不会.

解决办法:给DIV设定IE、FF两个宽度,在IE的宽度前加上IE特有标记” * “号。

2, 页面居中问题.

body {TEXT-ALIGN: center;} 在IE下足够了,但FF下失效。

解决办法:加上”MARGIN-RIGHT: auto; MARGIN-LEFT: auto; ”

3, 有的时候在IE6上看见一些奇怪的间隙,可我们高度明明设好了呀。

解决办法:试试在有空隙的DIV上加上”font-size:0px;”

4, 关于手形光标. cursor: pointer. 而hand 只适用于 IE.

5, 浮动IE6产生的双倍距离

#box{ float:left;
width:100px;
margin:0 0 0 100px;
}
这种情况之下IE6会产生200px的距离

解决办法:加上display:inline,使浮动忽略

这里细说一下block,inline两个元素,Block元素的特点是:总是在新行上开始,高度,宽度,行高,边距都可以控制(块元素);Inline元素的特点是:和其他元素在同一行上,…不可控制(内嵌元素);
#box{ display:block; //可以为内嵌元素模拟为块元素 display:inline; //实现同一行排列的的效果

6 页面的最小宽度

min- width是个非常方便的CSS命令,它可以指定元素最小也不能小于某个宽度,这样就能保证排版一直正确。但IE不认得min-这个定义,但实际上它把正常的width和height当作有min的情况来使。这样问题就大了,如果只用宽度和高度,正常的浏览器里 这两个值就不会变,如果只用min- width和min-height的话,IE下面根本等于没有设置宽度和高度。比如要设置背景图片,这个宽度是比较重 要的。

解决办法:为了让这一命令在IE上也能用,可以把一个<div> 放到 <body> 标签下,然后为div指定一个类:
然后CSS这样设计:
#container{
min-width: 600px;
width:expression(document.body.clientWidth < 600? “600px”: “auto” );
}
第一个min-width是正常的;但第2行的width使用了Javascript,这只有IE才认得,这也会让你的HTML文档不太正规。它实际上通过Javascript的判断来实现最小宽度。

7、UL和FORM标签的padding与margin

ul标签在FF中默认是有padding值的,而在IE中只有margin默认有值。FORM标签在IE中,将会自动margin一些边距,而在FF中margin则是0;

解决办法:css中首先都使用这样的样式ul,form{margin:0;padding:0;}给定义死了,后面就不会为这个头疼了.

8 ,DIV浮动IE文本产生3象素的bug

下面这段是我在网上粘过来的

左边对象浮动,右边采用外补丁的左边距来定位,右边对象内的文本会离左边有3px的间距.
#box{
float:left;
width:800px;}
#left{
float:left;
width:50%;}
#right{
width:50%;
}
*html #left{
margin-right:-3px;
//这句是关键
}
HTML代码
<DIV id=box>
<DIV id=left></DIV>
<DIV id=right></DIV>
</DIV>

针对上面这段代码,下面说一下我的理解:

第一、只要right定义了width属性,在FF下绝对就会两行显示
第二、两个width都定义为百分比的话,就算都为100%在IE下也会一行显示。所以上面那句所谓“这句是关键”根本没用,不加也在一行,除非你width定义的是数值才用得上。

所以说上面这段代码其实用处不大,至少在FF下不行。其实只要只定义left的width就行了,right不定义width就不管在IE还是FF下都能成功,但这样的话父DIV BOX并没有真正的包含LEFT和RIGHT两子DIV,可以用我上面说的第5种办法解决。最简单的办法就是在RIGHT中加上 float:left就OK了,真磨叽!

9,截字省略号

.hh { -o-text-overflow:ellipsis;
text-overflow:ellipsis;
white-space:nowrap;
overflow:hidden;
}
这个是在越出长度后会自行的截掉多出部分的文字,并以省略号结尾。技术是好技术,很多人都喜欢乱用,但注意Firefox并不支持。

解决办法:暂无!

一月 11th, 2010

理解正则表达式

1 Comment, 随笔记录, by admin.

rex注:本文原作者孟岩,原文转自孟岩CSDN博客。本文为《程序员》07年3月号《七种武器》专题所做。rex以前只是知道如何使用正则表达式而已,在读MRE时,读到NFA、DFA其实都是一头雾水,不知所云。现在抓紧时间恶补基础知识,学习了些编译原理,这才有些明白。如今再看从源头讲正则表达式的文章,就心有戚戚了,呵呵。搜到好文章一篇,与大家分享。

在程序员日常工作中,数据处理占据了相当的比重。而在所有的数据之中,文本又占据了相当的比重。文本能够被人理解,具有良好的透明性,利于系统的开发、测试和维护。然而,易于被人理解的文本数据,机器处理起来就不一定都那么容易。文本数据复杂多变,特定性强,甚至是千奇百怪。因此,文本处理程序可谓生存环境恶劣。一般来说,文本处理程序都是特定于应用的,一个项目有一个项目的要求,彼此之间很难抽出共同点,代码很难复用,往往是“一次编码,一次运行,到处补丁”。其程序结构散乱丑陋,谈不上有什么“艺术性”,基本上与“模式”、“架构”什么的无缘。在这里,从容雅致、温文尔雅派不上用场,要想生存就必须以暴制暴。
事实上,几十年的实践证明,除了正则表达式和更高级的parser技术,在这样一场街头斗殴中别无利器。而其中,尤以正则表达式最为常用。所以,对于今天的程序员来说,熟练使用正则表达式着实应该是一种必不可少的基本功。然而现实情况却是,知道的人很多,善于应用的人却很少,而能够洞悉其原理,理智而高效地应用它的人则少之又少。大多数开发者被它的外表吓倒,不敢也不耐烦深入了解其原理。事实上,正则表达式背后的原理并不复杂,只要耐心学习,积极实践,理解正则表达式并不困难。下面列举的一些条款,来自我本人学习和时间经验的不完全总结。由于水平和篇幅所限,只能浮光掠影,不足和谬误之处,希望得到有识之士的指教。

1. 了解正则表达式的历史
正则表达式萌芽于1940年代的神经生理学研究,由著名数学家Stephen Kleene第一个正式描述。具体地说,Kleene归纳了前述的神经生理学研究,在一篇题为《正则集代数》的论文中定义了“正则集”,并在其上定义了一个代数系统,并且引入了一种记号系统来描述正则集,这种记号系统被他称为“正则表达式”。在理论数学的圈子里被研究了几十年之后,1968年,后来发明了UNIX系统的Ken Thompson第一个把正则表达式用于计算机领域,开发了qed和grep两个实用文本处理工具,取得了巨大成功。在此后十几年里,一大批一流计算机科学家和黑客对正则表达式进行了密集的研究和实践。在1980年代早期,UNIX运动的两个中心贝尔实验室和加州大学伯克利分校分别围绕grep工具对正则表达式引擎进行了研究和实现。与之同时,编译器“龙书”的作者Alfred Aho开发了Egrep工具,大大扩展和增强了正则表达式的功能。此后,他又与《C程序设计语言》的作者Brian Kernighan等三人一起发明了流行的awk文本编辑语言。到了1986年,正则表达式迎来了一次飞跃。先是C语言顶级黑客Henry Spencer以源代码形式发布了一个用C语言写成的正则表达式程序库(当时还不叫open source),从而把正则表达式的奥妙带入寻常百姓家,然后是技术怪杰Larry Wall横空出世,发布了Perl语言的第一个版本。自那以后,Perl一直是正则表达式的旗手,可以说,今天正则表达式的标准和地位是由Perl塑造的。Perl 5.x发布以后,正则表达式进入了稳定成熟期,其强大能力已经征服了几乎所有主流语言平台,成为每个专业开发者都必须掌握的基本工具。

2. 掌握一门正则表达式语言
使用正则表达式有两种方法,一种是通过程序库,另一种是通过内置了正则表达式引擎的语言本身。前者的代表是Java、.NET、C/C++、Python,后者的代表则是Perl、Ruby、JavaScript和一些新兴语言,如Groovy等。如果学习正则表达式的目标仅仅是应付日常应用,则通过程序库使用就可以。但只有掌握一门正则表达式语言,才能够将正则表达式变成编程的直觉本能,达到较高的水准。不但如此,正则表达式语言也能够在实践中提供更高的开发和执行效率。因此,有心者应当掌握一门正则表达式语言。

3. 理解DFA和NFA
正则表达式引擎分成两类,一类称为DFA(确定性有穷自动机),另一类称为NFA(非确定性有穷自动机)。两类引擎要顺利工作,都必须有一个正则式和一个文本串,一个捏在手里,一个吃下去。DFA捏着文本串去比较正则式,看到一个子正则式,就把可能的匹配串全标注出来,然后再看正则式的下一个部分,根据新的匹配结果更新标注。而NFA是捏着正则式去比文本,吃掉一个字符,就把它跟正则式比较,匹配就记下来:“某年某月某日在某处匹配上了!”,然后接着往下干。一旦不匹配,就把刚吃的这个字符吐出来,一个个的吐,直到回到上一次匹配的地方。
DFA与NFA机制上的不同带来5个影响:
1. DFA对于文本串里的每一个字符只需扫描一次,比较快,但特性较少;NFA要翻来覆去吃字符、吐字符,速度慢,但是特性丰富,所以反而应用广泛,当今主要的正则表达式引擎,如Perl、Ruby、Python的re模块、Java和.NET的regex库,都是NFA的。
2. 只有NFA才支持lazy和backreference等特性;
3. NFA急于邀功请赏,所以最左子正则式优先匹配成功,因此偶尔会错过最佳匹配结果;DFA则是“最长的左子正则式优先匹配成功”。
4. NFA缺省采用greedy量词(见item 4);
5. NFA可能会陷入递归调用的陷阱而表现得性能极差。

我这里举一个例子来说明第3个影响。

例如用正则式/perl|perlman/来匹配文本 ‘perlman book’。如果是NFA,则以正则式为导向,手里捏着正则式,眼睛看着文本,一个字符一个字符的吃,吃完 ‘perl’ 以后,跟第一个子正则式/perl/已经匹配上了,于是记录在案,往下再看,吃进一个 ‘m’,这下糟了,跟子式/perl/不匹配了,于是把m吐出来,向上汇报说成功匹配 ‘perl’,不再关心其他,也不尝试后面那个子正则式/perlman/,自然也就看不到那个更好的答案了。

如果是DFA,它是以文本为导向,手里捏着文本,眼睛看着正则式,一口一口的吃。吃到/p/,就在手里的 ‘p’ 上打一个钩,记上一笔,说这个字符已经匹配上了,然后往下吃。当看到 /perl/ 之后,DFA不会停,会尝试再吃一口。这时候,第一个子正则式已经山穷水尽了,没得吃了,于是就甩掉它,去吃第二个子正则式的/m/。这一吃好了,因为又匹配上了,于是接着往下吃。直到把正则式吃完,心满意足往上报告说成功匹配了 ‘perlman’。

由此可知,要让NFA正确工作,应该使用 /perlman|perl/ 模式。

通过以上例子,可以理解为什么NFA是最左子式匹配,而DFA是最长左子式匹配。实际上,如果仔细分析,关于NFA和DFA的不同之处,都可以找出道理。而明白这些道理,对于有效应用正则表达式是非常有意义的。
4. 理解greedy和lazy量词
由于日常遇到的正则表达式引擎全都是NFA,所以缺省都采用greedy量词。Greedy量词的意思不难理解,就是对于/.*/、/\w+/这样的“重复n”次的模式,以贪婪方式进行,尽可能匹配更多字符,直到不得以罢手为止。

举一个例子,以 /<.*>/ 模式匹配 ‘<book> <title> Perl Hacks </title> </book>\t’文本,匹配结果不是 ‘<book>’,而是 ‘<book> <title> Perl Hacks </title> </book>’。原因就在于NFA引擎以贪婪方式执行“重复n次”的命令。让我们来仔细分析一下这个过程。

条款3指出,NFA的模型是以正则式为导向,拿着正则式吃文本。在上面的例子里,当它拿着/.*/这个正则式去吃文本的时候,缺省情况下它就这么一路吃下去,即使碰到 ‘>’字符也不罢手——既然 /./ 是匹配任意字符, ‘>’ 当然也可以匹配!所以就尽管吃下去,直到吃完遇到结尾(包括\t字符)也不觉得有什么不对。这个时候它突然发现,在正则表达式最后还有一个 />/,于是慌了神,知道吃多了,于是就开始一个字符一个字符的往回吐,直到吐出倒数第二个字符 ‘>’,完成了与正则式的匹配,才长舒一口气,向上汇报,匹配字符串从第一个字符 ‘<’ 开始,到倒数第二个字符 ‘>’结束,即’<book> <title> Perl Hacks </title> </book>’。

Greedy量词的行为有时确实是用户所需要的,有时则不是。比如在这个例子里,用户可能实际上想得到的是 ‘book’ 串。怎么办呢?这时候lazy量词就派上用场了。把模式改为/<.*?>/就可以得到 ‘book’。这个加在 ‘*’号后面的 ‘?’ 把greedy量词行为变成lazy量词行为,从而由尽量多吃变为尽量少吃,只要吃到一个 ‘>’立刻停止。

问号在正则表达式里用途最广泛,这里是很重要的一个用途。

5. 理解backtracking
在条款4的基础上解释backtracking就很容易了。当NFA发现自己吃多了,一个一个往回吐,边吐边找匹配,这个过程叫做backtracking。由于存在这个过程,在NFA匹配过程中,特别是在编写不合理的正则式匹配过程中,文本被反复扫描,效率损失是不小的。明白这个道理,对于写出高效的正则表达式很有帮助。