深入浅出之正则表达式(一)

  正则表达式是个很好的东西。做为一个程序员,掌握正则表达式是很有必要的。经人介绍,发现这个文章写得还是不错的,就转摘了过来。
  感谢翻译者的劳动和分享。下面是正文:

前言:
半年前我对正则表达式产生了兴趣,在网上查找过不少资料,看过不少的教程,最后在使用一个正则表达式工具RegexBuddy时发现他的教程写的非常好,可以说是我目前见过最好的正则表达式教程。于是一直想把他翻译过来。这个愿望直到这个五一长假才得以实现,结果就有了这篇文章。关于本文的名字,使用“深入浅出”似乎已经太俗。但是通读原文以后,觉得只有用“深入浅出”才能准确的表达出该教程给我的感受,所以也就不能免俗了。
本文是Jan Goyvaerts为RegexBuddy写的教程的译文,版权归原作者所有,欢迎转载。但是为了尊重原作者和译者的劳动,请注明出处!谢谢!

1.什么是正则表达式

基本说来,正则表达式是一种用来描述一定数量文本的模式。Regex代表Regular Express。本文将用<>来表示一段具体的正则表达式。

一段文本就是最基本的模式,简单的匹配相同的文本。

2.不同的正则表达式引擎

正则表达式引擎是一种可以处理正则表达式的软件。通常,引擎是更大的应用程序的一部分。在软件世界,不同的正则表达式并不互相兼容。本教程会集中讨论Perl 5 类型的引擎,因为这种引擎是应用最广泛的引擎。同时我们也会提到一些和其他引擎的区别。许多近代的引擎都很类似,但不完全一样。例如.NET正则库,JDK正则包。

3.文字符号

最基本的正则表达式由单个文字符号组成。如<>,它将匹配字符串中第一次出现的字符“a”。如对字符串“Jack is a boy”。“J”后的“a”将被匹配。而第二个“a”将不会被匹配。

正则表达式也可以匹配第二个“a”,这必须是你告诉正则表达式引擎从第一次匹配的地方开始搜索。在文本编辑器中,你可以使用“查找下一个”。在编程语言中,会有一个函数可以使你从前一次匹配的位置开始继续向后搜索。

类似的,<>会匹配“About cats and dogs”中的“cat”。这等于是告诉正则表达式引擎,找到一个<>,紧跟一个<>,再跟一个<>。

要注意,正则表达式引擎缺省是大小写敏感的。除非你告诉引擎忽略大小写,否则<>不会匹配“Cat”。

·特殊字符

对于文字字符,有11个字符被保留作特殊用途。他们是:

[ ] ^ $ . | ? * + ( )

这些特殊字符也被称作元字符。

如果你想在正则表达式中将这些字符用作文本字符,你需要用反斜杠“”对其进行换码 (escape)。例如你想匹配“1+1=2”,正确的表达式为<<1+1=2>>.

需要注意的是,<<1+1=2>>也是有效的正则表达式。但它不会匹配“1+1=2”,而会匹配“123+111=234”中的“111=2”。因为“+”在这里表示特殊含义(重复1次到多次)。

在编程语言中,要注意,一些特殊的字符会先被编译器处理,然后再传递给正则引擎。因此正则表达式<<1+2=2>>在C++中要写成“1\+1=2”。为了匹配“C: emp”,你要用正则表达式<>。而在C++中,正则表达式则变成了“C:\\temp”。

·不可显示字符

可以使用特殊字符序列来代表某些不可显示字符:

<< >>代表Tab(0x09)
<< >>代表回车符(0x0D)
<< >>代表换行符(0x0A)

要注意的是Windows中文本文件使用“
”来结束一行而Unix使用“
”。

4.正则表达式引擎的内部工作机制

知道正则表达式引擎是如何工作的有助于你很快理解为何某个正则表达式不像你期望的那样工作。

有两种类型的引擎:文本导向(text-directed)的引擎和正则导向(regex-directed)的引擎。Jeffrey Friedl把他们称作DFA和NFA引擎。本文谈到的是正则导向的引擎。这是因为一些非常有用的特性,如“惰性”量词(lazy quantifiers)和反向引用(backreferences),只能在正则导向的引擎中实现。所以毫不意外这种引擎是目前最流行的引擎。

你可以轻易分辨出所使用的引擎是文本导向还是正则导向。如果反向引用或“惰性”量词被实现,则可以肯定你使用的引擎是正则导向的。你可以作如下测试:将正则表达式<>应用到字符串“regex not”。如果匹配的结果是regex,则引擎是正则导向的。如果结果是regex not,则是文本导向的。因为正则导向的引擎是“猴急”的,它会很急切的进行表功,报告它找到的第一个匹配 。

·正则导向的引擎总是返回最左边的匹配

这是需要你理解的很重要的一点:即使以后有可能发现一个“更好”的匹配,正则导向的引擎也总是返回最左边的匹配。

当把<>应用到“He captured a catfish for his cat”,引擎先比较<>和“H”,结果失败了。于是引擎再比较<>和“e”,也失败了。直到第四个字符,<>匹配了“c”。<>匹配了第五个字符。到第六个字符<>没能匹配“p”,也失败了。引擎再继续从第五个字符重新检查匹配性。直到第十五个字符开始,<>匹配上了“catfish”中的“cat”,正则表达式引擎急切的返回第一个匹配的结果,而不会再继续查找是否有其他更好的匹配。

5.字符集

字符集是由一对方括号“[]”括起来的字符集合。使用字符集,你可以告诉正则表达式引擎仅仅匹配多个字符中的一个。如果你想匹配一个“a”或一个“e”,使用<<[ae]>>。你可以使用<>匹配gray或grey。这在你不确定你要搜索的字符是采用美国英语还是英国英语时特别有用。相反,<>将不会匹配graay或graey。字符集中的字符顺序并没有什么关系,结果都是相同的。

你可以使用连字符“-”定义一个字符范围作为字符集。<<[0-9]>>匹配0到9之间的单个数字。你可以使用不止一个范围。<<[0-9a-fA-F] >>匹配单个的十六进制数字,并且大小写不敏感。你也可以结合范围定义与单个字符定义。<<[0-9a-fxA-FX]>>匹配一个十六进制数字或字母X。再次强调一下,字符和范围定义的先后顺序对结果没有影响。

·字符集的一些应用

查找一个可能有拼写错误的单词,比如<> 或 <>。

查找程序语言的标识符,<>。(*表示重复0或多次)

查找C风格的十六进制数<<0[xX][A-Fa-f0-9]+>>。(+表示重复一次或多次)

·取反字符集

在左方括号“[”后面紧跟一个尖括号“^”,将会对字符集取反。结果是字符集将匹配任何不在方括号中的字符。不像“.”,取反字符集是可以匹配回车换行符的。

需要记住的很重要的一点是,取反字符集必须要匹配一个字符。<>并不意味着:匹配一个q,后面没有u跟着。它意味着:匹配一个q,后面跟着一个不是u的字符。所以它不会匹配“Iraq”中的q,而会匹配“Iraq is a country”中的q和一个空格符。事实上,空格符是匹配中的一部分,因为它是一个“不是u的字符”。

如果你只想匹配一个q,条件是q后面有一个不是u的字符,我们可以用后面将讲到的向前查看来解决。

·字符集中的元字符

需要注意的是,在字符集中只有4个 字符具有特殊含义。它们是:“] ^ -”。“]”代表字符集定义的结束;“”代表转义;“^”代表取反;“-”代表范围定义。其他常见的元字符在字符集定义内部都是正常字符,不需要转义。例如,要搜索星号*或加号+,你可以用<<[+*]>>。当然,如果你对那些通常的元字符进行转义,你的正则表达式一样会工作得很好,但是这会降低可读性。

在字符集定义中为了将反斜杠“”作为一个文字字符而非特殊含义的字符,你需要用另一个反斜杠对它进行转义。<<[\x]>>将会匹配一个反斜杠和一个X。“]^-”都可以用反斜杠进行转义,或者将他们放在一个不可能使用到他们特殊含义的位置。我们推荐后者,因为这样可以增加可读性。比如对于字符“^”,将它放在除了左括号“[”后面的位置,使用的都是文字字符含义而非取反含义。如<<[x^]>>会匹配一个x或^。<<[]x]>>会匹配一个“]”或“x”。<<[-x]>>或<<[x-]>>都会匹配一个“-”或“x”。

·字符集的简写

因为一些字符集非常常用,所以有一些简写方式。

<>代表<<[0-9]>>;
<>代表单词字符。这个是随正则表达式实现的不同而有些差异。绝大多数的正则表达式实现的单词字符集都包含了<>。
<>代表“白字符”。这个也是和不同的实现有关的。在绝大多数的实现中,都包含了空格符和Tab符,以及回车换行符<< >>。

字符集的缩写形式可以用在方括号之内或之外。<>匹配一个白字符后面紧跟一个数字。<<[sd]>>匹配单个白字符或数字。<<[da-fA-F]>>将匹配一个十六进制数字。

取反字符集的简写

<<[S]>> = <<[^s]>>
<<[W]>> = <<[^w]>>
<<[D]>> = <<[^d]>>

·字符集的重复

如果你用“?*+”操作符来重复一个字符集,你将会重复整个字符集。而不仅是它匹配的那个字符。正则表达式<<[0-9]+>>会匹配837以及222。

如果你仅仅想重复被匹配的那个字符,可以用向后引用达到目的。我们以后将讲到向后引用。

6.使用?*或+ 进行重复

?:告诉引擎匹配前导字符0次或一次。事实上是表示前导字符是可选的。
+:告诉引擎匹配前导字符1次或多次
*:告诉引擎匹配前导字符0次或多次

<[A-Za-z][A-Za-z0-9]*>匹配没有属性的HTML标签,“<”以及“>”是文字符号。第一个字符集匹配一个字母,第二个字符集匹配一个字母或数字。

我们似乎也可以用<[A-Za-z0-9]+>。但是它会匹配<1>。但是这个正则表达式在你知道你要搜索的字符串不包含类似的无效标签时还是足够有效的。

·限制性重复

许多现代的正则表达式实现,都允许你定义对一个字符重复多少次。词法是:{min,max}。min和max都是非负整数。如果逗号有而max被忽略了,则max没有限制。如果逗号和max都被忽略了,则重复min次。

因此{0,}和*一样,{1,}和+ 的作用一样。

你可以用<<[1-9][0-9]___noise___ 1075>>匹配1000~9999之间的数字(“”表示单词边界)。<<[1-9][0-9]___noise___ 1074>>匹配一个在100~99999之间的数字。

·注意贪婪性

假设你想用一个正则表达式匹配一个HTML标签。你知道输入将会是一个有效的HTML文件,因此正则表达式不需要排除那些无效的标签。所以如果是在两个尖括号之间的内容,就应该是一个HTML标签。

许多正则表达式的新手会首先想到用正则表达式<< <.+> >>,他们会很惊讶的发现,对于测试字符串,“This is a first test”,你可能期望会返回,然后继续进行匹配的时候,返回

但事实是不会。正则表达式将会匹配“first”。很显然这不是我们想要的结果。原因在于“+”是贪婪的。也就是说,“+”会导致正则表达式引擎试图尽可能的重复前导字符。只有当这种重复会引起整个正则表达式匹配失败的情况下,引擎会进行回溯。也就是说,它会放弃最后一次的“重复”,然后处理正则表达式余下的部分。

和“+”类似,“?*”的重复也是贪婪的。

·深入正则表达式引擎内部

让我们来看看正则引擎如何匹配前面的例子。第一个记号是“<”,这是一个文字符号。第二个符号是“.”,匹配了字符“E”,然后“+”一直可以匹配其余的字符,直到一行的结束。然后到了换行符,匹配失败(“.”不匹配换行符)。于是引擎开始对下一个正则表达式符号进行匹配。也即试图匹配“>”。到目前为止,“<.+”已经匹配了“first test”。引擎会试图将“>”与换行符进行匹配,结果失败了。于是引擎进行回溯。结果是现在“<.+”匹配“first tes”。于是引擎将“>”与“t”进行匹配。显然还是会失败。这个过程继续,直到“<.+”匹配“first”与“>”匹配。于是引擎找到了一个匹配“first”。记住,正则导向的引擎是“急切的”,所以它会急着报告它找到的第一个匹配。而不是继续回溯,即使可能会有更好的匹配,例如“”。所以我们可以看到,由于“+”的贪婪性,使得正则表达式引擎返回了一个最左边的最长的匹配。

·用懒惰性取代贪婪性

一个用于修正以上问题的可能方案是用“+”的惰性代替贪婪性。你可以在“+”后面紧跟一个问号“?”来达到这一点。“*”,“{}”和“?”表示的重复也可以用这个方案。因此在上面的例子中我们可以使用“<.+?>”。让我们再来看看正则表达式引擎的处理过程。

再一次,正则表达式记号“<”会匹配字符串的第一个“<”。下一个正则记号是“.”。这次是一个懒惰的“+”来重复上一个字符。这告诉正则引擎,尽可能少的重复上一个字符。因此引擎匹配“.”和字符“E”,然后用“>”匹配“M”,结果失败了。引擎会进行回溯,和上一个例子不同,因为是惰性重复,所以引擎是扩展惰性重复而不是减少,于是“<.+”现在被扩展为“”。这次得到了一个成功匹配。引擎于是报告“”是一个成功的匹配。整个过程大致如此。

·惰性扩展的一个替代方案

我们还有一个更好的替代方案。可以用一个贪婪重复与一个取反字符集:“<[^>]+>”。之所以说这是一个更好的方案在于使用惰性重复时,引擎会在找到一个成功匹配前对每一个字符进行回溯。而使用取反字符集则不需要进行回溯。

最后要记住的是,本教程仅仅谈到的是正则导向的引擎。文本导向的引擎是不回溯的。但是同时他们也不支持惰性重复操作。

7.使用“.”匹配几乎任意字符

在正则表达式中,“.”是最常用的符号之一。不幸的是,它也是最容易被误用的符号之一。

“.”匹配一个单个的字符而不用关心被匹配的字符是什么。唯一的例外是新行符。在本教程中谈到的引擎,缺省情况下都是不匹配新行符的。因此在缺省情况下,“.”等于是字符集[^

](Window)或[^
]( Unix)的简写。

这个例外是因为历史的原因。因为早期使用正则表达式的工具是基于行的。它们都是一行一行的读入一个文件,将正则表达式分别应用到每一行上去。在这些工具中,字符串是不包含新行符的。因此“.”也就从不匹配新行符。

现代的工具和语言能够将正则表达式应用到很大的字符串甚至整个文件上去。本教程讨论的所有正则表达式实现都提供一个选项,可以使“.”匹配所有的字符,包括新行符。在RegexBuddy, EditPad Pro或PowerGREP等工具中,你可以简单的选中“点号匹配新行符”。在Perl中,“.”可以匹配新行符的模式被称作“单行模式”。很不幸,这是一个很容易混淆的名词。因为还有所谓“多行模式”。多行模式只影响行首行尾的锚定(anchor),而单行模式只影响“.”。

其他语言和正则

增加PJBlog2 v2.6 build 02 的重置用户密码功能

  今天一朋友在这我这博客上的用户名的密码忘了,让我找回来。我去后台用户管理里一看,没有修改用户信息的功能,再到数据库和程序里一看,也不是一般的加密,就干脆用他自带的加密再做一个重置用户密码的功能。
  做的过程中,对这个博客的后台管理程序的写法又熟悉了一点。
  东西做出来了,虽不是什么好东西,也不敢独享,将修改步骤写出来供大家参考:
  1、在common文件夹下的control.js里添加一函数:[code] function rePwd(id){
if (confirm('是否重置该用户的密码?')){
document.forms[0].whatdo.value=”RePwd”
document.forms[0].DelID.value=id
document.forms[0].submit()
}
}
[/code]
  2、修改根目录下的ConContent.asp
  在帐户管理的帐户列表的适当处增加一列,在其中增加一个链接,代码如下:[code])”>重置密码[/code]
  若想作得美观点,可以像删除一样做一个小图片,再加上链接。
  在ConContent.asp找到以下代码(大概在2330行)[code] session(CookieName&”_ShowMsg”)=true
session(CookieName&”_MsgText”)=”“”&DelUserName&”” 删除成功!”
Response.Redirect(“ConContent.asp?Fmenu=Members&Smenu=Users”)
[/code]
在后面加上以下代码:[code] '————————重置密码为123456,By Lee 2007.06.29
elseif Request.form(“whatdo”)=”RePwd” then
dim ReUserID,ReUserName,strSalt,password
ReUserID=Request.form(“DelID”)
strSalt=randomStr(6)
password=SHA1(“123456″&strSalt)
ReUserName=conn.execute(“select mem_Name from blog_Member where mem_ID=”&ReUserID)(0)
conn.execute(“update blog_Member set mem_Password='”&password&”',mem_salt='”&strSalt&”' where mem_ID=”&ReUserID)
session(CookieName&”_ShowMsg”)=true
session(CookieName&”_MsgText”)=”“”&ReUserName&”” 的密码成功重置为123456!”
Response.Redirect(“ConContent.asp?Fmenu=Members&Smenu=Users”)
[/code]
  好了,大功告成了!

  和我用同个版本的朋友且自己没有修改过这两个文件的也可以下载下面的附件覆盖一下相同的文件。
common文件夹下的control.js:
[down=attachments/month_0706/82007629224123.rar]点击下载此文件[/down]
根目录下的ConContent.asp
[down=attachments/month_0706/t2007629224135.rar]点击下载此文件[/down]

  适用于PJBlog2 v2.6 build 02 ,其它版本的,可以按此思路来做。
  希望此文能解你破密码之苦。
  有问题请留言!

[color=Blue]更新:[/color]
无需登录,重置用户密码,对于忘了管理员密码的朋友很有帮助:
[down=attachments/month_0706/resetPwd.rar]点击下载此文件[/down]

[asp]让你知道codepage的重要

作者:萧萧小雨

这几天研究UTF-8编码,太晕了,把我的看法和各位讨论讨论。
欢迎来批啊。以下都是我的想法,哪里有不对的请不吝赐教,帮忙指出来。

相关的题外话:

一、操作系统
window系统内部都是unicode的。文件夹名,文件名等都是unicode的,任何语言系统下都能正常显示。

二、输入法:
微软拼音输出的是Unicode的,智能ABC输出是简体中文的(所以智能ABC在非简体中文系统根本不能用,只能打英文)。

三、网页的textarea
网页的textarea是用unicode显示的。所以往里打什么字都能显示。而一些flash做的输入框就不行了。

四、Access2000
access里面保存的数据是unicode的,在任何语言系统下都能显示。
如果数据视图查看有些字符不正常,那是因为显示所用的字体不是Unicode字体,
换用Arial Unicode MS 字体就能全部显示了。(access帮助,搜索,输入unicode,有说明)

五、Word
word里的繁简转换,简体转换到繁体后,内码仍是简体中文的,其实只是简体中的繁体字。

六、ASP内部是Unicode的,所有文本都是Unicode存储的。需要时转换到指定字符集。

首先说下结论:
&lt;%@ codepage=936%&gt;简体中文
&lt;%@ codepage=950%&gt;繁体中文
&lt;%@ codepage=65001%&gt;UTF-8

codepage指定了IIS按什么编码读取传递过来的串串(表单提交,地址栏传递等)。

也指定了所有文本变量从Unicode转换到的编码,
也就指定了从数据库取出的数据从Unicode转换到的编码。(注意这个,很重要。)

关键字:
读取:一个串串,按简体读取是一些字,按繁体读取是一些字,串串本身编码没有变。

转换:系统主动的转换,比如从Unicode的&ldquo;化&rdquo;字到Big5的&ldquo;化&rdquo;字,内码变成Big5的。如果Big5没有对应的字,保留Unicode形式(&amp;#xxxx;)

简体中文:化六个结论
Unicode16进制形式:&amp;#x5316;&amp;#x516d;&amp;#x4e2a;&amp;#x7ED3;&amp;#x8bba;
Unicode10进制形式:&amp;#21270;&amp;#20845;&amp;#20010;&amp;#32467;&amp;#35770;

下面是我推测出来的编码转换的过程:
客户端:输入法Unicode–输入框unicode–从Unicode按charset转换到对应编码()–表单发送编码

服务器端:IIS解开表单编码–按codepage指定编码读取–转换到对应的Unicode–可以用request(&quot;&quot;)读取了–进行一些处理–以Unicode编码保存到数据库

服务器端:读取数据库的Unicode数据,转换到codepage指定编码—生成源代码–IE按charset读取显示。

下面举例说明:
例一:
假设有三个asp页面,典型的留言页面:
1.write.asp 简单的输入表单,提交到add.asp。
&lt;META http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=big5&quot;&gt;
2.add.asp 接收留言,保存到数据库
&lt;%@ codepage=936%&gt;
3.read.asp 从数据库取得留言,显示。
&lt;%@ codepage=936%&gt; charset=GB2312 或
&lt;%@ codepage=950%&gt; charset=big5

大家可以猜一猜,我在write.asp里用微软拼音输入法输入&ldquo;化六个讨论&rdquo;。最后在read.asp里会显示什么样?
是不是晕了。让我们从头分析。

例二:
把例一的add.asp的&lt;%@ codepage=936%&gt;改为&lt;%@ codepage=950%&gt;,又会怎么样呢?

到这里发现了什么?
1.如果输入的文字和Charset对应的不同,一转换,就可能出现Unicode形式的字了。这里就是原因所在。以后整个过程都保留着。
2.Add.asp里codepage决定了保存到数据库的文字,用的是哪个语言对应的Unicode.如codepage=936,
那么数据库保存的就是简体中文的Unicode(数据库拿回简体中文系统,一切正常的),
codepage=950保存的就是繁体中文的Unicode.(拿回简体中文系统,就不对了)。

3.注意一下串串的变化过程:

1)输入法—CharsetUnicode—-指定字符集的映射
2)Charset—-表单编码串串简单编码
3)表单解码上步的逆过程,两步抵消了。
4)串串&agrave;按codepage读取串串没变,这步有可能&ldquo;误会读取&rdquo;
5)转为对应的Unicode Codepage指定字符集—-Unicode映射
6)中间处理,进数据库无变化,直接以Unicode形式进入
7)按codepage读取数据库 Unicode—-codepage指定字符集的映射
8)显示,按Charset指定字符集读取串串没变。

以例一说明:

例二:

晕了。现在来用用知识。

案例1。
简体中文系统下跑的好好的代码,放到国外空间上,数据库里乱码,原有的数据也乱码。
分析:因为大多数人平时用的都是简体中文系统,默认的codepage=936,所以平时大家不写也没有关系。
但到了国外空间问题就出来了。从数据库里的Unicode转换到英文编码去了,所以数据库原有的简体中文转换到英文后,按GB显示自然乱码。
如图,新输入的文字显示正常,但数据库里保存的是英文的Unicode的。
解决方法:全部加上&lt;%@codepage=936即可%&gt;。
全程只有简体中文与对应Unicode间的转换。

案例二:
简体中文的代码和数据,想转为完全的繁体版,该怎么办?
分析:1。代码文件编码全部改为Big5的,文件本身保存编码选繁体。
2.&lt;%@ codepage=936 %&gt;
3.Charset=big5
4.access版本无所谓,因为access里的数据是Unicode的。
5.好了,代码可以在纯繁体系统下跑了。
6.遗留问题:原有的简体中文数据读出会有一些问号。效果同例一的950读取,big5显示。因为从简体中文的Unicode转换到繁体中文了,有些字繁体中没有,就会出问号。
7.解决:用一个临时asp页,codepage=65001,读出为简体中文的Unicode,用一个Unicode-&gt;Big5的函数,转为繁体中文,然后写回数据库,应该行了吧?

两个案例完全是我按照理论推导出来了,未经证实。
有类似经历的欢迎批评指正。

ISAPI_Rewrite Examples

Examples
Emulating host-header-based virtual sites on a single site
For example you have registered two domains www.site1.com and www.site2.com. Now you can create two different sites using single physical site. Add the following rules to your httpd.ini file:

[ISAPI_Rewrite]

#Fix missing slash char on folders
RewriteCond Host: (.*)
RewriteRule ([^.?]+[^.?/]) http://$1$2/ [I,R]

#Emulate site1
RewriteCond Host: (?:www.)?site1.com
RewriteRule (.*) /site1$1 [I,L]

#Emulate site2
RewriteCond Host: (?:www.)?site2.com
RewriteRule (.*) /site2$1 [I,L]

Now just place your sites in /site1 and /site2 directories.

or you can use more generic rules:

[ISAPI_Rewrite]

#Fix missing slash char on folders
RewriteCond Host: (.*)
RewriteRule ([^.?]+[^.?/]) http://$1$2/ [I,R]

RewriteCond Host: (www.)?(.+)
RewriteRule (.*) /$2$3

The directory names for sites should be like /somesite1.com, /somesite2.info, etc.

Using different namespaces on development and live servers
Suppose you are developing rules for a website that will be deployed to a /livesite/ folder on a live server. However, on a development machine you need to store files in the /develop/ folder. In this case you could use UriMatchPrefix and UriFormatPrefix directives to minimize a number of changes those will be needed for a namespace change:

[ISAPI_Rewrite]

#specify namespaces with UriMatchPrefix and UriFormatPrefix
UriMatchPrefix /develop
UriFormatPrefix /develop

#rules are going here

#really we are checking for /develop/sampleN.htm and formatting to /develop/sampleN.asp
RewriteRule /sample1.htm /sample1.asp [I,L]
RewriteRule /sample2.htm /sample2.asp [I,L]
RewriteRule /sample3.htm /sample3.asp [I,L]

#reset namespaces to default
UriMatchPrefix
UriFormatPrefix

The only things you will need to change before a deployment to a live server are values of UriMatchPrefix and UriFormatPrefix.

Using loops (Next flag) to convert request parameters
Suppose you wish to access physical URLs like http://www.myhost.com/foo.asp?a=A&b=B&c=C using requests like http://www.myhost.com/foo.asp/a/A/b/B/c/C and the number of parameters may vary from one request to another.

There exist at least two possible solutions. You could simply add a separate rule for each possible number of parameters or you could use a technique demonstrated by the following example.

[ISAPI_Rewrite]
RewriteRule (.*?.asp)(?[^/]*)?/([^/]*)/([^/]*)(.*) $1(?2$2&:?)$3=$4$5 [NS,I]

Note that this rule may break page-relative links to CSSs, images, etc. This is due to a change in the base path (parent folder of the page) that is being used by a browser to calculate complete resource URI. There are three possible solutions:

Use the rule given below. It does not affect base path.
Directly specify correct base path for a page with the help of tag.
Change all page-relative links to either root-relative or absolute form.

This rule will extract one parameter from request URL, append it to the end of the request string and restart rules processing from the beginning. So it will loop until all parameters will be moved to the right place (or until the RepeatLimit will be exceeded).

There also exist many variations of this rule with different separator characters. For example, to use URLs like http://www.myhost.com/foo.asp~a~A~b~B~c~C the following rule could be implemented:

[ISAPI_Rewrite]
RewriteRule (.*?.asp)(?[^~]*)?~([^~]*)~([^~]*)(.*) $1(?2$2&:?)$3=$4$5 [NS,I]

Running servers behind IIS
Assume we have internet server running IIS and several corporate servers running other platform. These servers are not directly accessible from the internet but only from our corporate network. Here is a simple example how to map another server into the IIS site’s namespace using proxy flag:

[ISAPI_Rewrite]
RewriteProxy /mappoint(.+) http://sitedomain$1 [I,U]

Moving sites from UNIX to IIS
This rules can help change the URL from /~username to /username and /file.html to /file.htm. It can be useful if you just moved your site from UNIX to IIS and keep getting hits to the old pages from search engines and other external pages.

[ISAPI_Rewrite]

#redirecting to update old links
RewriteRule (.*).html $1.htm
RewriteRule /~(.*) http://myserver/$1 [R]

Moving site location
Many webmasters asked for a solution to the following problem: They want to redirect all requests to one web server to another web server. Such problems usually arise when you need to establish a newer web server which will replace the old one over time. The solution is to use ISAPI_Rewrite on the old web server:

[ISAPI_Rewrite]

#redirecting to update old links
RewriteRule (.+) http://newwebserver$1 [R]

Browser-dependent content
It is sometimes necessary to provide browser-dependent content at least for important top-level pages, i.e. one has to provide a full-featured version for the Internet Explorer, a minimum-featured version for the Lynx browsers and an average-featured version for all others.

We have to act on the HTTP header “User-Agent”. The sample code does the following: If the HTTP header “User-Agent” contains “MSIE”, the target foo.htm is rewritten to foo.IE.htm. If the browser is “Lynx” or “Mozilla” of version 1 or 2 the URL becomes foo.20.htm. Other browsers receive page foo.32.html. All this is done by the following ruleset:

[ISAPI_Rewrite]

RewriteCond User-Agent: .*MSIE.*
RewriteRule /foo.htm /foo.IE.htm [L]

RewriteCond User-Agent: (?:Lynx|Mozilla/[12]).*
RewriteRule /foo.htm /foo.20.htm [L]

RewriteRule /foo.htm /foo.32.htm [L]

Dynamically generated robots.txt
robots.txt is a file that search engines use to discover URLs that should or should not be indexed. But creation of this file for large sites with lot of dynamic content is a very complex task. Have you ever dreamed about dynamically generated robots.txt? Let's write robots.asp script:

<%@ Language=Jscript EnableSessionState=False%>
<%

//The script must return plain text
Response.ContentType=”text/plain”;

/*
Place generation code here
*/

%>

Now make it robots.txt using single rule:

[ISAPI_Rewrite]

RewriteRule /robots.txt /robots.asp

Making search engines to index dynamic pages
Content of the site stored in XML files. There is /XMLProcess.asp file that processes XML files on server and returns HTML to end user. URLs to the documents have a form of:
http://www.mysite.com/XMLProcess.asp?xml=/somdir/somedoc.xml
But many popular search engines will not index such documents because URLs contain question mark (document is dynamically generated). ISAPI_Rewrite can competely eliminate this problem.

[ISAPI_Rewrite]

RewriteRule /doc(.*).htm /XMLProcess.asp?xml=$1.xml

Now to access documents use URL like http://www.mysite.com/doc/somedir/somedoc.htm. Search engines will never know that physically there is no somedoc.htm file and content is dynamically generated.

Negative e­xpressions (NOT)
Sometimes you need to apply rule when some pattern not matches. In this case you may use so called Forward Lookahead Asserts in regular e­xpressions.

For example you need to move all users not using Internet Explorer to the other location:

[ISAPI_Rewrite]
# Redirect all non Internet Explorer users
# to another location
RewriteCond User-Agent: (?!.*MSIE).*
RewriteRule (.*) /nonie$1

Dynamic authentication
For example we have some members area on the site and we need password-protect files in this area but we don't like to use built-in server security. In this case it is possible to create ASP script (call it proxy.asp) that will proxy all requests to the members area and check for required permissions. Here is a simple template for this page where you can put your own authorization code:

<%@ Language=Jscript EnableSessionState=False%>
<%
function Authorize()
{

//Check if the user is authorized to view a resource here
//Return true if user has a required permission, otherwise return false

return true;
}
if(!Authorize())
{
//Redirect to the login page
Response.Redirect(“http://mysite.com/LoginPage.asp?ref=”+Request.QueryString.Item);
Response.End()
}
var WinHttpReq = new ActiveXObject(“WinHttp.WinHttpRequest.5”);
WinHttpReq.Open(Request.ServerVariables(“REQUEST_METHOD”).Item, Request.QueryString.Item, true);
var headers=String(Request.ServerVariables(“ALL_RAW”)).split(”
“);
for(i=0; i<headers.length && headers[i]; i++)
{
header = headers[i].match(/([w-.]+):s*([ S]*)/);
if(header)
WinHttpReq.SetRequestHeader(header[1],header[2]);
}
if(lngCount = Request.TotalBytes)
{
var data=Request.BinaryRead(lngCount);
WinHttpReq.Send(data);
} else {
WinHttpReq.Send();
}
if(!WinHttpReq.WaitForResponse(15))
{
WinHttpReq.Abort();
Response.Status=”408 Request Timeout”;
} else {
Response.Status = “” + WinHttpReq.Status + ” ” + WinHttpReq.StatusText;
headers=String(WinHttpReq.GetAllResponseHeaders()).split(”
“);
for(i=0; i<headers.length && headers[i]; i++)
{
header = headers[i].match(/([w-.]+):s*([ S]*)/);
if(header)
Response.AddHeader(header[1],header[2]);
}
Response.Write(WinHttpReq.ResponseText);
}
%>

Now we need to configure ISAPI_Rewrite to proxy requests through this page:

[ISAPI_Rewrite]
# Proxy all requests through proxy.asp
RewriteRule /members(.+) /proxy.asp?http://mysite.com/members$1

Blocking inline-images (stop hot linking)
Assume we have some pages with inlined GIF graphics under http://www.mysite.com/. These graphics are nice, so others directly incorporate them via hyperlinks to their pages. We don't like this practice because it adds useless traffic to our server.

While we cannot 100% protect the images from inclusion, we can at least restrict the cases where the browser sends a HTTP Referer header.

[ISAPI_Rewrite]
RewriteCond Host: (.+)RewriteCond Referer: (?!http://1.*).*RewriteRule .*.(?:gif|jpg|png) /block.gif [I,O]

Regular Expressions Testing Tool
RXTest utility could be used to simulate rule …

ISAPI_rewrite中文手册

配置:
在NT 2000 XP和2003平台上,在系统帐户下应该INETINFO程序应该与IIS5以共存模式过滤器运行。所以系统帐户应该给予对所有的ISAPI-REWIRITE DLLS 和所有的HTTPD。INI文件至少可读权限,我们也推荐对给予系统帐户对于所有包括HTTPD。INI文件的文件夹的可写权限,这将允许产生HTTP。PARSE。ERRORS文件,这些文件包含配置文件语法错误。对于PROXY模块也需要额外的权限,因为它将运行于连接池或HIGH-ISPLATED应用模式,IIS帐户共享池和HIGH-ISOLATION池应被给予 对RWHELPERE。DLL的可读权限。缺省情况下IWAM-《计算机名》被用于所有的池,在相应的COM+应用设置中应借助COM+ADMINISTRATION MMC SNAP-IN建立池帐户
配置文件格式化:

有两种形式的配置文件-GLOBAL(SERVER-LEVEL)和INDIVIDUAL(SITE-LEVAL)文件,GLOBAL配置文件应被命名为HTTPD.INI并出现在ISAPI-REWRITE安装目录中,文件的快捷方式通过开始菜单提供,INDIVIDUAL配置文件应名为HTTPD。INI并且能够出现在虚拟站点的物理根目录中,两种类型的格式化是相同的并是标准的WINDOWS。INI文件,所有的指令都应该放在这一部分并且所有指令都应该以分隔线放置,任何这一部分以外的文本都将被忽略

HTTPD.INI文件示例

[ISAPI_Rewrite]

# This is a comment

# 300 = 5 minutes
CacheClockRate 300
RepeatLimit 20

# Block external access to the httpd.ini and httpd.parse.errors files
RewriteRule /httpd(?:.ini|.parse.errors) / [F,I,O]

# Block external access to the Helper ISAPI Extension
RewriteRule .*.isrwhlp / [F,I,O]

# Some custom rules
RewriteCond Host: (.+)

RewriteCond 指令

Syntax:(句法) RewriteCond TestVerb CondPattern [Flags]
这一指令定义一个条件规则,在 RewriteRule 或者 RewriteHeader或 RewriteProxy指令前预行RewriteCond指令,后面的规则 只有它的,模式匹配URI的当前状态并且额外的条件也被应用才会被应用。

TestVerb

Specifies verb that will be matched against regular expression.
特别定义的动词匹配规定的表达式
TestVerb=(URL | METHOD | VERSION | HTTPHeaderName: | %ServerVariable) where:

URL – returns Request-URI of client request as described in RFC 2068 (HTTP 1.1);
返回客户端在RFC2068中描述的需求的Request-URI
METHOD – returns HTTP method of client request (OPTIONS, GET, HEAD, POST, PUT, Delete or TRACE);
返回客户端需求(OPTIONS, GET, HEAD, POST, PUT, Delete or TRACE)的HTTP方法
VERSION – returns HTTP version;
返回HTTP版本
HTTPHeaderName – returns value of the specified HTTP header. HTTPHeaderName can be any valid HTTP header name. Header names should include the trailing colon “:”. If specified header does not exists in a client's request TestVerb is treated as empty string.
返回特定义的HTTP头文件的值
HTTPHeaderName =
Accept:
Accept-Charset:
Accept-Encoding:
Accept-Language:
Authorization:
Cookie:
From:
Host:
If-Modified-Since:
If-Match:
If-None-Match:
If-Range:
If-Unmodified-Since:
Max-Forwards:
Proxy-Authorization:
Range:
Referer:
User-Agent:
Any-Custom-Header
得到更多的关于HTTP头文件的和他们的值的信息参考RFC2068

ServerVariable 返回特定义的服务器变量的值 。例如服务器端口,全部服务器变量列表应在IIS文档中建立,变量名应用%符预定;
CondPattern
The regular expression to match TestVerb
规则表达式匹配TestVerb
[Flags]
Flags is a comma-separated list of the following flags:

O (nOrmalize)
Normalizes string before processing. Normalization includes removing of an URL-encoding, illegal characters, etc. This flag is useful with URLs and URL-encoded headers
RewriteRule 指令
Syntax: RewriteRule Pattern FormatString [Flags]
这个指令可以不止发生一次,每个指令定义一个单独的重写规则,这些规则的定义命令很重要,因为这个命令在应用运行时规则是有用途的

I (ignore case)
不管大小写强行指定字符匹配,这个FLAG影响RewriteRule指令和相应的RewriteCond 指令
F (Forbidden)
对客户端做反应,停止REWRITING进程并且发送403错误,注意在这种情况下FORMATSTRING 是无用的并可以设置为任何非空字符串。
L (last rule)
不应用任何重写规则在此停止重写进程,使用这个FLAG以阻止当前被重写的URI被后面的规则再次重写
N (Next iteration)
强制REWRITINGENGINE调整规则目标并且从头重启规则检查(所有修改将保存),重启次数由RepeatLimit指定的值限制,如果这个数值超过N FLAG将被忽略
NS (Next iteration of the same rule)
以N标记工作不从相同的规则重启规则规则进程(例如强制重复规则应用),通过RepeatLimit指令指定一个反复实行某一规则的最大数目,
P (force proxy)
强制目的URI在内部强制为代理需求并且立即通过ISAPI扩展应付代理需求,必须确认代理字符串是一个有效的URI包括协议 主机等等否则代理将返回错误
R (explicit redirect)
强制服务器对客户端发出重定向指示即时应答,提供目的URI的新地址,重定向规则经常是最后规则
RP (permanent redirect)
几乎和[R]标记相同但是发布301HTTP状态而不是302HTTP状态代码
U (Unmangle Log)
当URI是源需求而不是重写需求时记载URI
O (nOrmalize)
在实行之前标准化字符串。标准化包括URL-ENCODING,不合法的字符的再移动等,这个标记对于URLS和URLS-ENDODED头是有用的
CL (Case Lower)
小写
CU (Case Upper)
大写
RewriteHeader directive
Syntax: RewriteHeader HeaderName Pattern FormatString [Flags]
这个指令是RewriteRule的更概括化变种,它不仅重写URL的客户端需求部分,而且重写HTTP头,这个指令不仅用于重写。生成,删除任何HTTP头,甚至改变客户端请求的方法
HeaderName
指定将被重写的客户头,可取的值与 RewriteCond 指令中TestVerb参数相同

Pattern
限定规则表达式以匹配Request-URI,
FormatString
限定将生成新的URI的FormatString
[Flags]
是一个下列FLAGS的命令分隔列表
I (ignore case)
不管大小写强行指定字符匹配,这个FLAG影响RewriteRule指令和相应的RewriteCond 指令
F (Forbidden)
对客户端做反应,停止REWRITING进程并且发送403错误,注意在这种情况下FORMATSTRING 是无用的并可以设置为任何非空字符串。
L (last rule)
不应用任何重写规则在此停止重写进程,使用这个FLAG以阻止当前被重写的URI被后面的规则再次重写
N (Next iteration)
强制REWRITINGENGINE调整规则目标并且从头重启规则检查(所有修改将保存),重启次数由RepeatLimit指定的值限制,如果这个数值超过N FLAG将被忽略

NS (Next iteration of the same rule)
以N标记工作不从相同的规则重启规则规则进程(例如强制重复规则应用),通过RepeatLimit指令指定一个反复实行某一规则的最大数目,

R (explicit redirect)
强制服务器对客户端发出重定向指示即时应答,提供目的URI的新地址,重定向规则经常是最后规则
RP (permanent redirect)
几乎和[R]标记相同但是发布301HTTP状态而不是302HTTP状态代码
U (Unmangle Log)
当URI是源需求而不是重写需求时记载URI
O (nOrmalize)
在实行之前标准化字符串。标准化包括URL-ENCODING,不合法的字符的再移动等,这个标记对于URLS和URLS-ENDODED头是有用的
CL (Case Lower)
小写
CU (Case Upper)
大写

要重移动头,FORMAT STRING模式应该生成一个空字符串,例如这一规则将从客户请求中重移代理信息
RewriteHeader User-Agent: .* $0
并且这一规则将把OLD-URL HEADER 加入请求中。
RewriteCond URL (.*)RewriteHeader Old-URL: ^$ $1
最后一个例子将通过改变请求方法定向所有的WEBDAV请求到/WEBDAV。ASP
RewriteCond METHOD OPTIONS
RewriteRule (.*) /webdav.asp?$1
RewriteHeader METHOD OPTIONS GET
RewriteProxy directive
Syntax: RewriteProxy Pattern FormatString [Flags]
强制目的URI在内部强制为代理需求并且立即通过ISAPI扩展应付代理需求,这将允许IIS作为代理服务器并且重路由到其他站点和服务器
Pattern
限定规则表达式以匹配Request-URI,
FormatString
限定将生成新的URI的FormatString
[Flags]
是一个下列FLAGS的命令分隔列表
D (Delegate security)
代理模式将试图以当前假冒的用户资格登陆远程服务器,
C (use Credentials)
代理模式将试图一在URL或基本授权头文件中指定的资格登陆远程服务器,用这个标记你可以使用http://user:password@host.com/path/ syntax 作为URL
F (Follow redirects)
缺省情况下ISAPI_Rewrite 将试图将MAP远程服务器返回的重定向指令到本地服务器命名空间,如果远程服务器返回重定向点到那台服务器其他的某个位置,ISAPI_Rewrite 将修改这一重定向指令指向本服务器名,这将避免用户看到真实(内部)服务器名称
使用F标记强制代理模式内部跟踪远程服务器返回的重定向指令,使用这个标记如果你根本不需要接受远程服务器的重定向指令,在WINHTTP设置中有重定向限制以避免远程重定向循环
I (ignore case)
不管大小写强行指定字符匹配
U (Unmangle Log)
当URI是源需求而不是重写需求时记载URI
O (nOrmalize)
在实行之前标准化字符串。标准化包括URL-ENCODING,不合法的字符的再移动等,这个标记对于URLS和URLS-ENDODED头是有用的
CacheClockRate directive
Syntax: CacheClockRate Interval
这个指令只在GLOBAL配置内容中出现,如果这个指令在SITE-LEVEL内容中出现将被忽略并把错误信息写入httpd.parse.errors 文件
ISAPI_Rewrite caches每次在第一次加载时配置,使用这个指令你可以限定当一个特定站点从缓存中清理的不活动周期,把这个参数设置的足够大你可以强制ISAPI_Rewrite 永不清理缓存,记住任何配置文件的改变将在下次请求后立即更新而忽略这个周期
Interval
限定特定配置被清理出缓存的不作为时间(以秒计),缺省值3600(1小时)
EnableConfig and DisableConfig directives
Syntax:
EnableConfig [SiteID|”Site name”]
DisableConfig [SiteID|”Site name”]
对所选站点激活或不激活SITE-LEVEL配置或者改变缺省配置,缺省SITE-LEVEL配置不激活,这个指令只出现在GLOBAL配置内容中
SiteID
Numeric metabase identifier of a site

Site name
Name of the site as it appears in the IIS console
不用参数使用这个命令将改变缺省配置到ENABLE/DISABLE配置进程
例子
下面例子将使配置仅作用于ID=1(典型是缺省站点)名字是MY SITE的站点
DisableConfig
EnableConfig 1
EnableConfig”My site”
下边例子将激活名称为SOMESITE配置因为它分割设置重载了缺省设置
EnableConfig”Some site”
DisableConfig
EnableRewrite and DisableRewrite directives
Syntax:
EnableRewrite [SiteID|”Site name”]
DisableRewrite [SiteID|”Site name”]
对所选站点激活或不激活重写或者改变缺省配置,缺省重写配置激活,这个指令只出现在GLOBAL配置内容中
SiteID
Numeric metabase identifier of a site

Site name
Name of the site as it appears in the IIS console.

不使用参数这个命令将全部激活或者不激活
RepeatLimit directive
Syntax: RepeatLimit Limit
这个指令可以出现在GLOBAL和SITE-LEVEL配置文件中,如果出现在GLOBAL配置文件中竟改变GLOBAL对于所有站点的限制,出现在SITE-LEVEL配置中竟只改变对于这个站点的限制并且这个限制不能超过GLOBAL限制
ISAPI_Rewrite在实行规则时允许循环,这个指令允许限制最大可能循环的数量,可以设置为0或1而不支持循环,
LIMIT
限制最大循环数量,缺省32
RFStyle directive
Syntax: RFStyle Old | New
Configuration Utility
ISAPI_Rewrite Full包括配置功用(可以在 ISAPI_Rewrite 程序组中启动),它允许你浏览测试状态并输入注册码(如果在安装过程中没有注册),并且调整部分与代理模式操作相关的产品功能,UTILITY是由三个页面组成的属性表
Trial page允许你浏览TIRAL状态并输入注册码(如果在安装过程中没有注册)
Settings page
这页包含对下列参数的编辑框

Helper URL
这个参数影响过滤器和代理模块之间的联系方式,它即可以是以点做前缀的文件扩展名(如 .isrwhlp)也可以是绝对路径,
第一种情况下扩展名将追加在初始请求URI上并且代理模块竟通过SCRIPT MAP激活,缺省扩展名isrwhlp在安装进程中加在global script map 中,如果你改变这个扩展名或者你的应用不继承global script map 设置你应该手动添加向script map 所需求的入口。这个应该有如下参数
Executable: An absolute path to the rwhelper.dll in the short form
Extension: Desired extension (.isrwhlp is default)
Verbs radio button: All Verbs
Script engine checkbox: Checked
Check that file exists checkbox: Unchecked
我们已经创建了一个WSH script proxycfg.vbs ,可以简单在一个a script maps中注册,她位于安装文件夹并且可以在命令行一如下方式运行
cscript proxycfg.vbs [-r] [MetabasePath]
Optional -r 强制注册扩展名
Optional MetabasePath parameter allows specification of the first metabase key to process. By default it is “/localhost/W3SVC”.
要在所有现存的 script maps 中注册你可以以如下命令行激活 script
cscript proxycfg.vbs -r
第二种情况下你应该提供一个URI作为'Helper URL'的值,你也应该map 一个 ISAPI_Rewrite的安装文件夹作为美意个站点的虚拟文件家
注意:根据顾客反应,IIS5(也许包括IIS4)对长目录名有问题。所以我们强烈推荐使用短目录名
Worker threads limit
这个参数限制在代理扩展线程池中工作线程数,缺省为0意味着这个限制等于处理器数量乘以2
Active threads limit
这个参数限制当前运行线程数,这个数量不可大于”Worker threads limit”. 缺省0意思是等于处理器数量
Queue size 这个参数定义最大请求数量,如果你曾经看到Queue timeout expired” 信息在 the Application event log中你可以增加这个参数
Queue timeout
这个参数定义你在内部请求队列中防止新请求的最大等待时间,如果你曾经看到Queue timeout expired” 信息在 the Application event log中你可以增加这个参数
Connect timeout
以毫秒设定代理模块连接超时
Send timeout
以毫秒设定代理模块发送超时
Receive timeout
以毫秒设定代理模块发送超时
About page.
It contains copyright information and a link to the ISAPI_Rewrite's web site.

Regular expression syntax
这一部分覆盖了 ISAPI_Rewrite规定的表达句法
Literals
所有字符都是原意除了 “.”, “*”, “?”, “+”, “(“, “)”, “{“, “}”, “[“, “]”, “^” and “$”.,这些字符在用“”处理时是原意,原意指一个字符匹配自身
Wildcard
The dot character “.” matches any single character except null character and newline character
以下为句法
Repeats
A repeat is an expression that is repeated an arbitrary number of times. An expression followed by “*” can be repeated any number of times including zero. An expression followed by “+” can be repeated any number of times, but at least once. An expression followed by “?” may be repeated zero or one times only. When it is necessary to specify the minimum and maximum number of repeats explicitly, the bounds operator “{}” may be used, thus “a{2}” is the letter “a” repeated exactly twice, “a{2,4}” represents the letter “a” repeated between 2 and 4 times, and “a{2,

web交互界面易用性设计和验收的指导性原则

. 输入控件的自动聚焦和可用键盘切换输入焦点

使用JavaScript实现页面加载完成后立即自动聚焦(focus)到第一个输入控件。可用TAB键(IE缺省实现)或方向键切换聚焦到下一个输入控件。

  输入控件指WEB页面表单(&lt;form&gt;)中显式的,需要用户进行修改、编辑操作的表单元素。对于这些控件,如果没有自动聚焦操作,不可避免的出现一次用户鼠标定位操作(如果用户此前处于键盘输入操作状态或鼠标定位后需要进行键盘输入操作,实际上是键盘鼠标切换操作)。如果鼠标定位后需要进行键盘输入操作,如果不能键盘切换输入焦点,那么不可避免的在切换输入焦点时需要反复的键盘鼠标切换操作,这是很繁琐的。

  如果实现了页面加载完成即自动聚焦到第一个输入控件,并且可以键盘切换输入焦点标定位操作,那么对于用户来说整个页面的输入操作可能都不需要鼠标操作,或次数较少,这是一种便利。毕竟频繁的键盘鼠标切换操作是比较累人的。

  对于有输入栏的对话框或网页,在不干预的情况下就应将当前控制焦点定位在待输入的输入栏上;如果输入栏在一般情况下不需要更改其中的内容,则应直接将焦点定在&ldquo;确定&rdquo;按钮上;在几个输入栏之间应支持tab,shift+tab切换操作,&ldquo;确定&rdquo;和&ldquo;取消&rdquo;应该是切换操作的终点,与具体所在位置无关。

  2. 可用Enter(或Ctrl+Enter)键提交,确保和点击提交按钮的效果是相同的

  不要在提交按钮上加入onClick=&rdquo;&hellip;&rdquo;这样的JavaScript代码。

  用Enter键提交页面是原则1的自然延伸,而且这也是浏览器所缺省支持的。只所以单独列出来是因为实际上有些设计者设计的页面不能达到这种效果,结果导致使用Enter键提交和点击&ldquo;确定&rdquo;按钮提交带来的效果不一样。大部分情况下是设计者在&ldquo;确定&rdquo;按钮上加入了onClik=&rdquo;&hellip;&rdquo;这样的代码,通过点击&ldquo;确定&rdquo;按钮后,会执行一段JavaScript代码,比如对某些hidden类型的input元素设值。而使用Enter键提交时就不会执行这段代码。

  正确的做法是把这段代码移到表单标签&lt;form&gt;中,以onSubmit=&rdquo;&hellip;&rdquo;属性引入。

  对于&lt;textarea&gt;表单元素,它会消耗Enter键,因此会使得Enter键提交失效。可以引入JavaScript代码捕捉Ctrl+Enter复合键,一旦捕捉到即执行表单的submit()方法。对于需要频繁提交的场合,比如BBS上,这种代码是很有必要的。

  3. 鼠标动作提示和回应

  对用户的鼠标定位操作,当移动到可响应的位置上时,应给予视觉或听觉的提示。

  动作回应的最简单形式就是鼠标ICON变成手状。浏览器只对具有href属性的HTML标签会自动进行这种变换ICON的行为。对于没有href属性(或没有设置href属性)的标签,可以通过JavaScript设置style属性的cursor为hand。

  目标区域发生变化是更为主动的响应形式。当鼠标指针移到目标区域,此时指针图形改变或文字颜色发生改变均能较大的减轻用户搜索定位目标区域的注意力负担。在按钮上增添直观的图形,尽可能的增大按钮面积;按钮间保持适当的距离,太近增加了用户区别它们之间界限以防误操作的负担,太远增加了用户搜索定位按钮的负担。

  4.尽可能早的在客户端完成输入数据合法性验证

  输入数据的合法性检验应该在客户端使用JavaScript进行验证。除非验证只能在服务器端完成,否则验证工作应在最早能完成的情况下进行。

  在客户端完成数据合法性验证,可以避免一次服务器请求和回复通讯,这种通讯是需要用户等待的,如果用户等待很长时间后从服务器返回的结果提示出现的错误是在输入时即可发现的,那么这种设计就是不友好的。诸如密码长度限制,用户名允许字符限制等等,显然应该在客户端提交前就应该进行验证。

  5. 根据应用场景决定在表单页面和提交后返回页面间是否使用中间过渡页面

  根据应用场景,决定是否显示接收表单页面(表单页面和提交后返回页面间的中间过渡页面),以及使用何种方式显示接收表单页面。

  表单页面和接收表单页面是大部分WEB交互操作赖以实现的配合模式。关于表单页面和接收表单页面的相互关系的设计,要做如下几个方面的考虑。

  一,对于需要频繁操作的场合,从操作便利和快捷性出发,尽可能的减少服务器和客户端交互次数,应该避免使用中间过渡页面。提交完毕直接返回原来的表单页面或默认页面。在这种情况下要考虑到数据安全和可恢复性。

  如果因为用户输入的数据不合格,需要重新输入,那么,去除中间页面,把错误信息直接显示在原表单页面上的设计方式,将是最简洁的处理方式。用户只需要根据错误提示进行更正即可。当然这样做稍微增加了编程负担。在表单接收页面上需要包含原表单页面的内容,而且输入数据项都必须用服务器端代码或客户端JavaScript设置成用户输入的值。为了开发快捷,可以这样做:表单页面和接收表单页面用同一个服务器端脚本页面实现。这个页面按如下流程完成原来两个页面的工作:

页面脚本初始化

检查&ldquo;提交&rdquo;变量是否设置
┠已设置,做数据验证
┃ ┠验证通过-&gt;业务逻辑处理-&gt;使用包含页面方式或重定向方式返回到特定页面&nbsp;
┃ ┗验证不通过-&gt;保存用户输入的数据-&gt;退出表单提交处理到表单页面流程中
┗未设置,做表单页面流程,如有来自提交流程中产生的用户输入数据,则显示出来

  其中,使用包含页面方式返回到特定页面可以避免一次客户端重定向过程,比客户端重定向过程还要快捷和稳定一些。但是有些情况下因为代码变量冲突或其他原因,使用包含页面方式可能并不方便,这时候可以使用服务器端重定向技术,在ASP里是Server.Transfer方法,在Java Servlet里是RequestDispatcher.forward()方法。不要使用Response.Redirect或者HttpServletResponse.sendRedirect()这种客户端HTTP重定向方法。不使用中间过渡页面也就意味着用户不能后退浏览原先已经填好的表单页面,因为使用的是同一个URL。所以在验证不通过情况下保存用户输入的数据就是必不可少的。

  不使用中间过渡页面带来的另一个问题就是使用包含页面方式或服务器端重定向方式返回会使得URL和页面内容不能一一对应。对于用户可能会直接用这个URL(会收藏这个URL)访问返回页面的情况,他会发现实际上到达的是表单页面,不是他想要的那个返回结果页面。所以,去除中间过渡页面,确实会带来URL和内容含混不清的情况,因而不适合需要URL和页面内容一一对应的场合。

  二,从技术角度考虑,使用中间过渡页面能保证URL和页面内容一一对应,简化页面开发工作。

  为了保证页面内容总是和固定的URL联系起来,必须使用客户端重定向:

提交 业务逻辑处理 (中间过渡页面)
表单页面――――-&gt;接收表单页面―――――――――&gt;显示处理结果―――&gt;客户端重定向到特定页面

  客户端重定向分几种情况:1,使用HTTP Header重定向,Location:http://www.netall.com.cn,这种定向是最快的,在窗口一片空白的情况下就迅速访问(GET)另一个页面。这种方式实际上不能显示处理结果,只能说是向第一种快速重定向方式的一种折衷处理;2,HTML标签刷新,&lt;META HTTP-EQUIV=&quot;Refresh&quot; CONTENT=&quot;5;URL=http://www.netall.com.cn&quot;&gt;,这种定向比较友好,在这个页面加载完毕后访问另一个页面。很多设计者把这个作为一个技巧使用,在载入一个大页面前放置一个缓冲页面以避免用户乏味的等待;3,JavaScript重定向。由于是用代码控制重定向,可以做的更灵活。比如根据用户习惯,控制操作完毕后的转向流程。4,被动式的重定向。在页面上放置按钮或链接,由用户手动决定返回到特定页面。这种情况适合于处理结果的显示页面包含相当多的信息,需要用户仔细浏览,而决定下一步的操作。

  在使用中间过渡页面的情况下,不能再使用页面过期失效了。否则一旦出现错误,需要用户重新输入表单数据,用户就不能用后退按钮恢复此前填写的表单数据了。除非设计者有意禁止这种恢复。

  6. 防止表单重复提交处理

  对提交按钮点击后做变灰处理避免在网络响应较慢情况下用户重复提交同一个表单。使用页面过期失效避免用户后退浏览重复提交表单。

  有些复杂的应用会导致需要较长时间的等待才会返回处理结果。而在较慢的网络环境中,这种情况更是频繁发生。焦急等待的用户往往会重复点击提交按钮。这种情况是设计者所不希望看到的。

  使用JavaScript在点击提交按钮后使按钮失效变灰是一个最直接的办法(根据原则2这段代码应该放在&lt;form&gt;标签里onSubmit=&rdquo;&hellip;&rdquo;做)。此外,在表单页面上,用服务器端脚本设置HTTP Header的Expires为立即过期可以保证用户没办法使用后退浏览恢复表单页面。注意这样做的代价可能是用户辛辛苦苦填写很长的内容,结果一旦操作失误就没法恢复。所以应该避免在包含&lt;textarea&gt;表单元素的页面上使用页面过期失效。

  应该说,更严格的方法是,服务器端脚本就应该具备抵抗重复提交的能力。例如,为这个表单分配一个唯一ID或一个使用一次即失效的验证码。此外,这个表单处理还应具有事务性质,如果表单不被接受,所做的改变还是能恢复的。在金融应用场合,重复提交同一笔交易是肯定不被允许的。能在重复提交中获利的一方总是会想办法绕过浏览器的限制,所以不能依赖于客户端的技术。

  7. 页面链接是打开新窗口、使用原窗口还是弹出窗口的原则

  一般而言,首页上链接可以使用target=&rdquo;_blank&rdquo;属性打开新窗口,而其他页面上的链接都应使用原窗口或弹出窗口。如果链接页面内容相对原页面来说不重要,是附属性质的,可以使用弹出窗口方式。

  一般情况下应该使用原窗口,把是否保留原窗口内容的权利留给用户。除非设计者相信原页面是如此重要,在用户发出点击指令后还有使用上的价值,以至于不能被随便更新或覆盖。一般来说,只有首页才会处于这样一个地位,用户在首页上打开一个链接后,一般还会在这个首页上去打开另一个链接。比如首页包含极多链接的门户网站,或者搜索引擎的搜索结果页面。Google.com以前的搜索结果页面上的链接是使用原窗口的,后来他们意识到用户会反复使用这个页面,而改成打开新窗口了。一般的网站如果首页链接不多,就不必使用新窗口,这是用户友好的设计原则。

  上述情形的一个极端情况就是新页面内容比起原页面内容的重要性差很多,以至于都未必需要打开一个新页面。这时候使用弹出窗口比较合适。用JavaScript弹出窗口有好几种:一个是window.open()函数。这里有个技巧。应该使用window.open()先打开一个空白窗口,再使用location.replace()用目标页面替换。这样做可以避免在打开新页面的过程中导致原页面失去响应。Window.open()将打开一个新的浏览器窗口进程,因此资源消耗比较大。另一个是由微软DynamicHTML规范中扩充的方法createPopup()。createPopup()可以创建无边框的弹出窗口,消耗系统资源较小。还有一个就是用页面中隐藏的层&lt;div&gt;来模拟一个弹出页面。后两种可以使用JavaScript代码填充弹出窗口内容。如果需要下载网页作为其内容的话,需要微软DynamicHTML规范中的&lt;download&gt;标签。

google adsense的一些准则

google adsense产品的一些原则

1.永远不要作弊(太老土了)
2.每个申请帐号的地址只能对应一个人名,用家里人身份证申请的,注意了.
3.不要试图在同一台机器上面登录多个帐号.身在外地的站长,想看数据的时候忍忍吧,千万别用站长朋友的机器登录,小心连坐.建议使用报表功能把多个帐号的收入每天发送到指定邮箱.
4.保持自己所用机器的干净,不要点击任何google的广告.
5.如果非要点几个广告,登录几个帐号,请先清理机器上面所有浏览器的临时文件和cookie,并且彻底更换IP
6.互点必死
7.用干净的网站注册帐号,google不在乎你是否把广告放在这个网站上.
8.网站有色情内容100%被封.版权内容可以在你认识google的人的情况下做.
9.收入上升过快必死
10.google如果要k号,永远跟作弊无关.google只在乎效果是否好,并不在乎你是否作弊(其实跟第一条并没有冲突,可以慢慢理解)
11.google投放出来的所有广告,均会监控转化率,转换率达不到一定标准一定被k号.就算不被k号,也会被降权.(具体比例就不说了)
12.google近来在拼命推一个产品,叫做Google Analytics,想必很受站长们的欢迎.大家知道这个东西的主要作用是什么吗?k号.说白了就是用来监控广告的转化率和监控你是否作弊.嘿嘿,怕了吧.

google adsense的一些优化规则
1.目前国内效果最好的广告样式是小方块
2.每个页面上面的广告个数不要超过3个.google广告的价格是按照出现时间递减.也就是说,最先出来的广告价格最高,然后每个价格越来越低
3.google广告可以跟其他广告(比如百度)等放同一个页面.

IIS 占用 CPU %问题排查方案

有时候辛辛苦苦写个网站,挂到服务器上一看,CPU给百分百了,这种问题百分之八九十都是因为代码写有问题,而不是因为系统设置的问题,这种问题也比较难排查。但是结合一些工具也可以找到原因的,关于windbg的使用,好像有本关于.net调试的书,大家有兴趣可以看看,网上也有一些帖子,但关于ANTS Profiler的帖子就比较少了,大家也可以下载试用版来帮助解决问题

1 准备日志
1.1 用perfmon添加计数器日志,添加如下计数器

ASP.NET:所有计数器
Memory:所有计数器
Process:所有计数器和所有实例
Processor:所有计数器和所有实例
Thread:所有计数器和所有实例
Web service:所有计数器和所有实例

1.2 间隔改成1,单位改成秒

1.3 用鼠标右键单击这个日志名,然后单击开始。确保日志捕获了处理器利用率猛增至 100% 的那段时间内的所有数据。

2  抓Dump
2.1 用IIS Diagnostics Toolkit工具找出占用CPU高的w3wp进程ID

2.2 用windbg执行以下命令adplus –hang –p pid并抓取dump

3 检查日志
3.1 识别哪一个进程消耗了大部分的 CPU 时间

用perfmon打开准备好的日志文件,用鼠标右键单击图表,然后单击添加计数器。在添加计数器对话框中,从性能对象列表中选择 Process。选择从列表中选择计数器,然后从此列表框中选择 %Processor Time。选择所有实例,单击添加,然后单击关闭。

这将为我们提供所有处理器及其 CPU 使用情况的列表。现在您需要查清哪个进程引起了 100% 的 CPU 问题。

确保选中了突出显示工具按钮(黄色灯泡图标)。现在您可以滚动这些计数器,将除最接近 100% 标记的那个进程之外的所有进程全部删除。确保只选择了那些与您有关系的计数器。例如,如果您正在调试 100% 的 CPU 利用率的问题,您也许应该查找w3wp、inetinfo、其它的脱机处理的 COM 程序包/应用程序 (MTX.EXE/DLLHOST.EXE) 或者 IIS 应用程序。

3.2 找出该进程内部的那些在出现 100% 的 CPU 问题时仍然活动的线程实例

一旦您在进程级将问题隔离出来,您就可以将注意力集中在该进程内部的那些在出现 100% 的 CPU 问题时仍然活动的线程上,并试着隔离引起问题的那个线程。为此,我们添加更多的计数器来显示该进程中所有线程的 CPU 使用情况。对于本例而言,就是为w3wp进程(假设它占用CPU最高)中的所有线程添加计数器。用鼠标右键单击图表,然后单击添加计数器。在添加计数器对话框中,从性能呢个对象列表中选择 Thread。选择从列表中选择计数器,然后从列表框中选择 %Processor Time。选择 从列表中选择实例,然后选择以 w3wp/* 开头的所有实例。单击添加,然后单击关闭。

这时,图表中显示在w3wp进程中的所有线程的 CPU 使用情况。

现在可以滚动计数器,将除最接近 100% 标记的那个线程以外的所有线程全部删除。这样我们就准确地找到了引起问题的那个线程(假设它的线程实例ID为12)。

3.3 找出导致CPU占用100%的线程ID

我们只保留实例ID 为12的线程(上一步操作留下的那个线程),它占用了最长的 CPU 时间。现在必须找出这个线程的线程 ID,然后在 WinDBG 中找到这个线程并对它进行调试。

要找出线程 ID,请用鼠标右键单击图表,然后单击添加计数器。在添加计数器对话框中,从心能对象列表中选择 Thread。选择从列表中选择计数器,然后从此列表框中选择 ID Thread。选择从列表中选择实例,然后选择实例w3wp/12(看具体情况而定)。单击添加,然后单击关闭。

这样我们就得到了引起问题的那个线程的 ID。选择 ID Thread 计数器。记录该计数器的最后一个值、最大值、最小值和平均值。通常这四个数是相同的。记录这个值(比如说1460),并切换到 WinDBG 应用程序。

4  找出导致CPU占用100%的相关代码
4.1 打开windbg,点击菜单File/Open Crash Dump,选择第二步用Adplus抓的dump文件

在 WinDBG 的 View 菜单上,单击 Processes and Threads。这将显示在出现 100% 的 CPU 问题时在w3wp进程内部运行的线程的一个列表。查找您在性能监视器中记录的线程 ID 号(3.3步中找到的线程ID,这个ID是十进制的,用calc换算成16进制标识)。如果在列表中找到此 ID 号(16进制),则单击选中它。单击 OK。

在 View 菜单上,单击 Call Stack。这时显示引起问题的那个线程的堆栈。该堆栈将有问题的方法隔离出来。一旦我们找到这个方法,我们就可以返回原代码,查看是哪行代码引起这个问题的。

十步学会用CSS+DIV建站

原作者Steve Dennis,翻译Jorux

目录:

第一步:规划网站,本教程将以图示为例构建网站;

第二步:创建html模板及文件目录等;

第三步:将网站分为五个div,网页基本布局的基础;

第四步:网页布局与div浮动等;

第五步:网页主要框架之外的附加结构的布局与表现;

第六步:页面内的基本文本的样式(css)设置;

第七步:网站头部图标与logo部分的设计;

第八步:页脚信息(版权等)的表现设置;

第九步:导航条的制作(较难);

第十步:解决IE浏览器的显示BUG;

第一步:规划网站,本教程将以图示为例构建网站

1.规划网站,本教程将以下图为例构建网站。

divlayout

点击看大图

其基本布局见下图:

divlayout

点击看大图

主要由五个部分构成:

1.Main Navigation 导航条,具有按钮特效。 Width: 760px Height: 50px

2.Header 网站头部图标,包含网站的logo和站名。 Width: 760px Height: 150px

3.Content 网站的主要内容。 Width: 480px Height: Changes depending on content

4.Sidebar 边框,一些附加信息。 Width: 280px Height: Changes depending on

5.Footer 网站底栏,包含版权信息等。 Width: 760px Height: 66px

第二步:创建html模板及文件目录等

1.创建html模板。代码如下:

&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;
&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv=&quot;Content-type&quot; content=&quot;text/html; charset=UTF-8&quot; /&gt;
&lt;title&gt;CompanyName – PageName&lt;/title&gt;
&lt;meta http-equiv=&quot;Content-Language&quot; content=&quot;en-us&quot; /&gt;
&lt;meta http-equiv=&quot;imagetoolbar&quot; content=&quot;no&quot; /&gt;
&lt;meta name=&quot;MSSmartTagsPreventParsing&quot; content=&quot;true&quot; /&gt;
&lt;meta name=&quot;description&quot; content=&quot;Description&quot; /&gt;
&lt;meta name=&quot;keywords&quot; content=&quot;Keywords&quot; /&gt;
&lt;meta name=&quot;author&quot; content=&quot;Enlighten Designs&quot; /&gt;
&lt;style type=&quot;text/css&quot; media=&quot;all&quot;&gt;@import &quot;css/master.css&quot;;&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;/body&gt;
&lt;/html&gt;

将其保存为index.html,并创建文件夹css,images,网站结构如下:

layout

2.创建网站的大框,即建立一个宽760px的盒子,它将包含网站的所有元素。
在html文件的&lt;body&gt;和&lt;/body&gt;之间写入

&lt;div id=&quot;page-container&quot;&gt;
Hello world.
&lt;/div&gt;

创建css文件,命名为master.css,保存在/css/文件夹下。写入:

#page-container {
width: 760px;
background: red;
}

控制html的id为page-container的盒子的宽为760px,背景为红色。表现如下:
layout
现在为了让盒子居中,写入margin: auto;,使css文件为:

#page-container {
width: 760px;
margin: auto;
background: red;
}

现在你可以看到盒子和浏览器的顶端有8px宽的空隙。这是由于浏览器的默认的填充和边界造成的。消除这个空隙,就需要在css文件中写入:

html, body {
margin: 0;
padding: 0;
}

第三步:将网站分为五个div,网页基本布局的基础:

&nbsp;

1.将&ldquo;第一步&rdquo;提到的五个部分都放入盒子中,在html文件中写入:

&lt;div id=&quot;page-container&quot;&gt;
&lt;div id=&quot;main-nav&quot;&gt;Main Nav&lt;/div&gt;
&lt;div id=&quot;header&quot;&gt;Header&lt;/div&gt;
&lt;div id=&quot;sidebar-a&quot;&gt;Sidebar A&lt;/div&gt;
&lt;div id=&quot;content&quot;&gt;Content&lt;/div&gt;
&lt;div id=&quot;footer&quot;&gt;Footer&lt;/div&gt;
&lt;/div&gt;

表现如下:
lay
2.为了将五个部分区分开来,我们将这五个部分用不同的背景颜色标示出来,在css文件写入:

#main-nav {
background: red;
height: 50px;
}
#header {
background: blue;
height: 150px;
}
#sidebar-a {
background: darkgreen;
}
#content {
background: green;
}
#footer {
background: orange;
height: 66px;
}

表现如下:
lay

第四步:网页布局与div浮动等:

1.浮动,首先让边框浮动到主要内容的右边。用css控制浮动:

#sidebar-a {
float: right;
width: 280px;
background: darkgreen;
}

表现如下:
lay

2.往主要内容的盒子中写入一些文字。在html文件中写入:

&lt;div id=&quot;content&quot;&gt;
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam gravida enim ut risus.
Praesent sapien purus, ultrices a, varius ac, suscipit ut, enim. Maecenas in lectus.
Donec in sapien in nibh rutrum gravida. Sed ut mauris. Fusce malesuada enim vitae lacus
euismod vulputate. Nullam rhoncus mauris ac metus. Maecenas vulputate aliquam odio.
Duis scelerisque justo a pede. Nam augue lorem, semper at, porta eget, placerat eget,
purus. Suspendisse mattis nunc vestibulum ligula. In hac habitasse platea dictumst.
&lt;/div&gt;

表现如下:
lay
但是你可以看到主要内容的盒子占据了整个page-container的宽度,我们需要将#content的右边界设为280px。以使其不和边框发生冲突。
css代码如下:

#content {
margin-right: 280px;
background: green;
}

同时往边框里写入一些文字。在html文件中写入:

&lt;div id=&quot;sidebar-a&quot;&gt;
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam gravida enim ut risus.
Praesent sapien purus, ultrices a, varius ac, suscipit ut, enim. Maecenas in lectus.
Donec in sapien in nibh rutrum gravida. Sed ut mauris. Fusce malesuada enim vitae lacus
euismod vulputate. Nullam rhoncus mauris ac metus. Maecenas vulputate aliquam odio.
Duis scelerisque justo a pede. Nam augue lorem, semper at, porta eget, placerat eget,
purus. Suspendisse mattis nunc vestibulum ligula. In hac habitasse platea dictumst.
&lt;/div&gt;

表现如下:
lay
这也不是我们想要的,网站的底框跑到边框的下边去了。这是由于我们将边框向右浮动,由于是浮动,所以可以理解为它位于整个盒子之上的另一层。因此,底框和内容盒子对齐了。
因此我们往css中写入:

#footer {
clear: both;
background: orange;
height: 66px;
}

表现如下:
lay

第五步:网页主要框架之外的附加结构的布局与表现:

第五步主要介绍除网页主要框架之外的附加结构的表现(Layout),包括以下内容:
1.主导航条;
2.标题(heading),包括网站名和内容标题;
3.内容;
4.页脚信息,包括版权,认证,副导航条(可选)。

加入这些结构时,为了不破坏原有框架,我们需要在css文件&quot;body&quot;标签(TAG)下加入:

.hidden {
display: none;
}

&quot;.hidden&quot;即我们加入的类(class),这个类可以使页面上任意属于hidden类的元素(element)不显示。这些会在稍后使用,现在请暂时忘记它。

现在我们加入标题(heading):
先回到HTML的代码,&lt;h1&gt;到&lt; h6&gt;是我们常用的html标题代码。比如我们一般用&lt;h1&gt;网站名&lt;/h1&gt;,&lt;h2&gt;网站副标题&lt; /h2&gt;,&lt;h3&gt;内容主标题&lt;/h3&gt;等。我们往html文件的Header层(Div)加入:

&lt;div id=&quot;header&quot;&gt;
&lt;h1&gt;Enlighten Designs&lt;/h1&gt;
&lt;/div&gt;

刷新一下页面,你就可以看到巨大的标题,和标题周围的空白,这是因为&lt;h1&gt;&gt;标签的默认大小和边距(margin)造成的,先要消除这些空白,需要加入:

h1 {
margin: 0;
padding: 0;
}

接下来是导航条
控制导航条表现的css代码相对比较复杂,我们将在第九步或是第十步中详细介绍。现在html文件加入导航代码:

&lt;div id=&quot;main-nav&quot;&gt;
&lt;ul&gt;
&lt;li id=&quot;about&quot;&gt;&lt;a href=&quot;http://css.jorux.com/wp-admin/post.php#&quot; &gt;About&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;services&quot;&gt;&lt;a href=&quot;http://css.jorux.com/wp-admin/post.php#&quot; &gt;Services&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;portfolio&quot;&gt;&lt;a href=&quot;http://css.jorux.com/wp-admin/post.php#&quot; &gt;Portfolio&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;contact&quot;&gt;&lt;a href=&quot;http://css.jorux.com/wp-admin/post.php#&quot; &gt;Contact Us&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

(注:原教程使用了dl和dt,jorux在这使用了更常用的ul和li标签)
目前导航条的表现比较糟糕,但是要在以后的教程中介绍其特殊表现,故需要暂时隐藏导航条,于是加入:

&lt;div id=&quot;main-nav&quot;&gt;
&lt;dl class=&quot;hidden&quot;&gt;
&lt;dt id=&quot;about&quot;&gt;&lt;a href=&quot;http://css.jorux.com/wp-admin/post.php#&quot; &gt;About&lt;/a&gt;&lt;/dt&gt;
&lt;dt id=&quot;services&quot;&gt;&lt;a href=&quot;http://css.jorux.com/wp-admin/post.php#&quot; &gt;Services&lt;/a&gt;&lt;/dt&gt;
&lt;dt id=&quot;portfolio&quot;&gt;&lt;a href=&quot;http://css.jorux.com/wp-admin/post.php#&quot; &gt;Portfolio&lt;/a&gt;&lt;/dt&gt;
&lt;dt id=&quot;contact&quot;&gt;&lt;a href=&quot;http://css.jorux.com/wp-admin/post.php#&quot; &gt;Contact Us&lt;/a&gt;&lt;/dt&gt;
&lt;/dl&gt;
&lt;/div&gt;

我们跳一步,先到页脚:
页脚包括两部分:左边的版权,认证和右边的副导航条。
我们先要让副导航条向右浮动,就像之前处理Sidebar和Content关系的一样,需要加入一个新的层(div):

&lt;div id=&quot;footer&quot;&gt;
&lt;div id=&quot;altnav&quot;&gt;
&lt;a href=&quot;http://css.jorux.com/wp-admin/post.php#&quot; &gt;About&lt;/a&gt; –
&lt;a href=&quot;http://css.jorux.com/wp-admin/post.php#&quot; &gt;Services&lt;/a&gt; –
&lt;a href=&quot;http://css.jorux.com/wp-admin/post.php#&quot; &gt;Portfolio&lt;/a&gt; –
&lt;a href=&quot;http://css.jorux.com/wp-admin/post.php#&quot; &gt;Contact Us&lt;/a&gt; –
&lt;a href=&quot;http://css.jorux.com/wp-admin/post.php#&quot; &gt;Terms of Trade&lt;/a&gt;
&lt

CSS 禅意花园主人 Dave Shea 访谈

  也许你没听说过他的名字,但是,如果你是个认真的网站设计师,一定听说过 [url=http://www.csszengarden.com/]CSS Zen Garden [/url](CSS 禅意花园) 这个站点。其构想很单纯 – 提供网页的源文件,人们可以用 CSS 将它设计成各式各样的风格并提交上来。它反映了时代的潮流,并立即吸引了顶尖平面设计师的注意力,激发了Web设计师学习掌握CSS的热情。为什么?看多了早期的标记语言大师们死板的设计,我们终于可以领略艺术家和平面设计师们用 CSS 所能达到的设计境界。
  因此,CSS ZenGarden 既是个画廊,又是个宣言。Dave写道:“很显然,CSS 应当引起平面设计师们的高度重视。禅意花园致力于推广使用、启发灵感和鼓励参与。”那么,Dave Shea 究竟是何许人也? DMXzone 的 Bruce Lawson 周末采访了他。

  [b]CSS 高手能成为设计师的很少见。你为什么要做一个“CSS 布道者”?[/b]
  和 Doug, Todd, Kris 和 Paul 一样,我不认为使用 CSS 设计出的作品注定都是丑陋的。只不过应该用好 CSS 的人现在还没理解到它的妙处而已。

  请看普通设计(如矢量图形或 Quicktime 影片之类的)和 CSS 设计在创作过程中的差异。设计师在电脑上所做的一切都是由 GUI(图形用户界面)实现的,当然要所见即所得。而 CSS 要写代码,这是两个完全不同的领域,问题的难点就在这里:你必须成为双面手才行。

  我最近看过许多关于编码与设计的讨论。有人说只有对底层的代码有深刻的了解,才能解决出现的问题。就浏览器对CSS的支持程度来看,这种说法不无道理。但在我看来还是传统的设计师学习 CSS 这个新玩艺儿的方法有问题。

  到了直观的CSS编辑器的出现以后,情况才会有所改观。基于表格的设计工具早就有了,采用 Dreamweaver 和 Fireworks 能够制作出相当漂亮的网站,不需要懂得很多的HTML语言。尽管代码看起来很乱,但能够取悦大多数客户。在CSS编辑器的功能和易用性赶上这些网页制作工具之前,可以想象让那些不堪代码学习之苦的设计师们采用CSS,肯定会遇到不少阻力。我们需要的是 CSS 的 InDesign,可是有谁肯做这件事?

  但是我不是这样的设计师,我不能坐等工具出现,所以就瞄准 Web 的发展趋势,向前迈了一大步。我知道只要追随 XML 就能完全彻底地将内容和呈现相分离。曙光已经出现,还把自己局限于上世纪九十年代后期的设计方法是很不明智的,迟早是会丢掉饭碗的。我要为将来 – 我自己的前途做些打算 。

  嗯,有意思。何不建个新站点,在第一时间去验证这个想法,既能达到 XHTML, CSS 和 508 条款的要求,又不必做什么改动。还有什么比它更能带来满足感呢?。

  [b]在黎明到来之前的日子里,web 设计师和 web 开发者的区别在哪里?你是哪一类?[/b]
  或许两样都算吧。我想 web 设计师的主要工作是在前台:设计,制作 Flash,编写 XHTML/CSS 代码和一点儿 JavaScript,偶尔还要写服务器端的代码。Web 开发者主要在后台与 PHP,Perl,MySQL,ASP,XML打交道,还要写 JavaScript 和 XHTML/CSS/XSLT 代码。交叉当然是有的,我看到人们在这两者之间苦苦挣扎,我不知道该怎么称呼他们。更别提什么信息架构师、易用性大师和亲和力专家了,这些名词儿太笼统,变化太快。

  我是个网站设计师。我并不喜欢这顶帽子,我对外开价时通常用的是“平面设计师”,只不过我的设计领域恰巧集中在 Web 领域而已。

  [b]为什么你对 Web 这个媒体如此投入和狂热?[/b]
  混沌产生秩序,不同声音的力量,以及大家都站在同一起跑线上。和普通的网志相比,我并不对传统媒体有什么偏爱。新闻记者们整天在炒作,而在与他人合作的过程中,我发现网上的朋友们同样(也许更加)值得信赖,我并不感到孤独。

  除此之外还有网络的全球性。只须通过点击鼠标,我就可以和哈萨克斯坦的人们一样访问同样的信息。去年我经常沿着北美的海岸线旅行,每次从飞机的机舱向外望去,我就情不自禁地去想象 Web 所包容的巨大空间,令人觉得这是如此平常,而又实在难以置信。

  [b]你制作的第一个网站是哪个?在你做过的网站中,你最喜欢哪一个?[/b]
  实际上我在服务器上发布的第一个正式网站是“digital gallery”,是1997年做的,不过都是一些 3D 渲染效果很差劲的JPG 图片。那时我刚刚放弃学了很久的 QuickBasic 编程,我觉得我的兴趣在平面设计上,而不是编程。所以我需要一个媒体,而在当时,Web 对我来说是个全新的东西。读了 Molly Holzschlag 的 Sizzling Web Design 以后,我发现这正是我的兴趣所在,甚至还谋到了一份这样的差事。六年后的今天,我仍然觉得其乐无穷,我猜我选对了媒体。

  至于最喜欢的站点,我对提交到禅意花园的每份作品都感到兴奋不已,我感到很高兴,因为从未有人提及我在 mezzoblue.com 工作。我每隔几年都去一趟温哥华的一家巧克力公司 “Over the Moon”,1999年我为他们设计了第一个网站,现在的网站是 2001年底到2002年初制作的。看过代码的人就会发现当时我还有使用表格的习惯,不过这是我第一次尝试 CSS/XHTML 混合布局,从底栏的验证链接就可以看出。为什么我最喜欢它?当然是可以享用免费的巧克力。

  [b]怎么会想到要发起 css 禅意花园?[/b]
这个设想第一次在我脑海中闪现是在2002年9月。当时我正在为一家公司工作,他们当时仍在为 Netscape 4.x 写代码,我试图向他们演示应该放弃那些过时的代码,面向未来所带来的好处。其实我已经开始着手做了,不过以后就没有下文了 [这可是本次采访的独家消息,之前从未有人见过]。

  到了第二年四月,Lycos 打算举办一个“Hack Hotbot”竞赛,内容是为搜索引擎制作 CSS “皮肤”。长话短说,我不喜欢他们的比赛条件,他们的代码非常恐怖,他们拒绝了我的参赛作品,只是因为我是加拿大人。

  尽管这项比赛的运作方式令人无法恭维,但对整个网站设计群体来说却是个好事。我的作品完成的同时,也明白了什么是 不应该做的。9月的那个主意还在我的脑海中盘旋,现在时机已经成熟,我把这些想法整理整理,要做就把它做好。

  我所看到的是一条鸿沟。一边是 K10k 和 PixelSurgeon 和 Dik 及其信徒们,这些以设计为中心的精美作品确实令人眼花缭乱;而另一边是 CSS 的拥趸,其数量少得多。

  总得有人为他们架起一座桥梁。我不认为我已经达到了这个目标,其实我明白来自顶尖设计群体的阻力。CSS 阵营的人们已经开始去赢得 CSS 与表格布局的这场战争,在他们看来,CSS Garden 就是一个坚强后盾。

  我并不赞成这种战争或者对立。基于表格布局的混合设计仍然有用武之地,而且是人们在实际工作中的一个技术上的选择。把宗教留给专家们,为客户做出最恰当的选择吧。

  [b]现在这个站点已经进入 Google 的“CSS”搜索结果前十名;究竟为何如此受人关注?[/b]
  也许我对 CSS 过于熟悉了,反而无法给出正确答案。对我来说,这个设想只不过是其他项目自然演化的结果,而对大多数人来说这是一场革命。我们有人非常清楚,用 CSS 完全可以做到这种结果,但极少有人真的去实践过。Chris Casciano 和 Jeremy Keith 是先行者之一。

  而对于其他人来说完全是大开眼界。很多人说根本想不到用 CSS 竟然可以做出这样的神奇效果,所以我猜,构思新颖是我们受人喜爱的原因之一。此外,各个作品的名字通俗易懂,汇集了各种相关资源,为渴望向人展示自己作品的设计师提供了一个场所。

  随着设计师不断提交来自己的作品,网站的内容也在不断地更新,每每有令人惊奇的作品出现,不再有人去读那些文字了,我们都想知道其中的奥秘,这份熟悉的 XHTML 文件,竟然有这么多令人瞠目的呈现形式。

  创新是灵感的火花,而熟悉的内容让其充满活力。

  [b]在这些作品中,你最喜欢哪个?[/b]
  用外交辞令来说,当然每份作品都非常优秀。如果你真的要我献出镇山之宝的话,我想 Didier Hilhorst 的 Release One, Radu Darvas 的 Zunflower, Doug Bowman 的 Golden Mean, 和 Mike Pick 的 What Lies Beneath 完全出乎我的想象。尽管其 CSS 技巧各有独到之处,但每件都是绝妙之作。

  上面提到的那些自然是实至名归。我非常喜爱从24号(Dan Rubin 的 Not So Minimal)到31号(Kev Mears 的 Hedges)这组作品,其中每件都创意独到、设计精美,是不可多得的佳作。

  私下来说,对尚未问世的作品的质量,我决不敢妄加揣测。说实话,与这些花园的园丁们一起工作,我有些受宠若惊并引以为荣。

  [b]你还开办了 mezzoblue 网站。为何选择 blue ?[/b]
  Blue 表达了我内心淡淡的忧郁。

  实际上,我还是相当乐观的人。2001年秋我为新域名经历了一次头脑风暴,我想到了许多与“冷”有关的主题如 PixelBlue、MezzoFrost等等。当时的感觉很好,不过现在我有些后悔,不该把自己局限于某个色板。我在站点最近一次的改版中采用了很有意思的配色方案,这算是我乐观的一面的体现吧。

  [b]说出你最喜爱的电影、音乐、建筑、比萨饼口味和外国话?[/b]
  目前我最喜欢的就是 Amélie / Itzhak Perlman 的小提琴独奏、洛克菲勒中心、加州比萨店的北京鸭和 merde。

  [b]你认为目前最顶尖的设计师有哪些?[/b]
  不久前我刚浏览了 Doug Bowman 的作品,我对妻子说:“你知道,看了别人的作品感到不安其实很好,它为你树立了一个赶超的目标。” Todd Dominey 和 Cuban Council/K10k 成员的大作总能令我开心。在向禅意花园提交那两份作品之前,我对 Mike Pick 还不很熟悉,但很快就迷上了他的大作。

  我喜欢去一些设计门户网站(surfstation.lu, pixelsurgeon.com, designiskinky.com)转转,欣赏一些创意独到、干净整洁的站点。但我和普通的访客并无二致,无法为此投入过多。

  IE 独立版本的停止开发和以及 Netscape 的终结,对现代的网页制作技术是好还是坏?
  这要看当时的情况变化,我很难说。

  乐观的是 Mozilla/Opera/Safari 能迅速填补留下的巨大空间,无线装置的迅速兴起使得对标准的支持变得前所未有的重要。在6年以内,如果还只为 IE6 打算就会带来小小的麻烦。

  最悲观的莫过于微软根本就不喜欢Web,随着他们的重点转移,我敢说不管他们在这个领域如何打算都是为了专属利益。由于他们压倒性的市场份额,我们还不得不迁就它。乐观的观点告诉我,微软不可能赢得这个游戏。公众对Web方式是如此喜欢,不会坐视他们釜底抽薪的。

  最近乐观派似乎占了上风,但情况并不非常令人满意。

  [b]如果按 1 (=最低) 到 10 (=最高) 来排名,你能排在第几位?[/b]
  我妻子大概会给我第12名。我好久没看过 Star Trek 了,我想不至于太差吧。其实不管怎么排名都是相对的,与本文的读者相比,我大概能排到第6位,但如果和大街上随便找来的人相比,肯定能排到第9。

  [b]Web 标准(CSS, XHTML 等等)是不是抬高了在 Web 上发布东西的门槛?[/b]
好问题。这个问题在我的个人邮件中也被问到过。我的回答是否定的,不过我很愿意参加这个问题的讨论。

  新手们不一定都得去学习 XHTML 和 CSS。1996年的HTML对他们一样管用,简单的文件包含的标记很少,仅此而已。抽象地谈论“将内容和呈现相分离”对他们来说意义不大。大多数新手压根儿就没写过一个标记,我们也不应对他们有过高的奢望。

  但是 Web 还是在向 XML 和上面提到的这种抽象层次发展,当然就提高了门槛。CSS 对Web的未来非常重要,对电脑知识知之甚少的家人在考虑层次和方块时所想到情景和 CSS 的原理是一样的。对,就是这样。

  所以,如果 Web 是为人人所用的,要是必须读懂大堆的书本和教材才能制作网页的话,一般的新手怎么可能在网上发布他们的家庭影集?

  许多年前就有一种服务来填补这个空缺了。你根本不用为发布网页发愁,你只须掌握 FTP 和目录结构就够了。这曾经是一个很大的障碍,大多新手们并不觉得很难。一些网站如 Fotki 和 Kodak 的 图片乐园提供了照片存储服务。目前锋头正劲的是 weblog,BlogSpot、TypePad 和 AOL Journals 的一条龙服务也是大势所趋。

  新手们无须知道我们将要改变的是作为 Web 根基的底层代码。尽管技术对他们而言并不重要,但当我看到 TypePad 从一开始就做到遵从标准时感到非常欣喜,我期待有更多的后来者效仿。

  [b]你是个设计师,我却不是。我完全支持 www.bancomicsans.com 要从地球上禁止使用 comic sans 字体的目标。你呢?[/b]
  啊,当然。一开始我以为是对字体抱有偏见的人开的玩笑,不过后来我注意到此人有一定道理。这种字体无处不在,我想把这都归罪于 Vincent Connare (Comic Sans MS 的设计者)是不公正的。不过我想这给各位设计师留下了一个教训:你的作品就代表你自己,不管你是否情愿。

  [b]假如你有一天成了全球的统治者,你还想禁止什么?[/b]
  越南咖啡和四巨头:雀巢、Sara Lee、P&G 和 卡夫。

  噢对了,我还要扔掉我的肥皂盒。

  [b]你的下一步打算?[/b]
  我还在探索之中。现在我正在为参与编写的“Cascading Style Sheets: Separating Content from Presentation”的出版作最后的润色。过不了多久也许会出一两本书,但目前还没有什么打算。

  此外,我的事业才刚刚起步。今年的年景不错,但这并不妨碍为前途做些打算。我想到温哥华的一个公司工作,他们完全理解 Web 的真义,而且已经做得不错了。这件事,我很愿意听听读者们的建议。

  [b]今天你看到的最美的东西是什么?[/b]
  我的新娘刚醒来时的笑容。

  [b]瞧这水杯:它是半满的,还是半空的?[/b]
  我想要个大杯子。

  Thanks Dave!