关于作者

用户名:xiaohuar
笔名:xiaohuar
地区:
行业:其他

日历  

快速登录

+ 用户名:
+ 密 码:

在线留言


最新评论

访问统计:
文章个数:4
评论个数:1
留言条数:14




Powered by BlogDriver 2.1

无效空间

 

文章

Unix(Linux)C编程问题精粹


=======================================
|版权声明:你可以自由复制与分发本文档||如果你要修改本文档或提出更好建议,请||先通知文章的作者。而不要仅在公告栏中||贴出。因为作者可能漏看。无论如何,都||须保留本声明.
=======================================

文章目录第一章:前言第二章:约定第三章:开始任务第四章:使用lint第五章:使用make第六章:优质无错编程第七章:调试技术第八章:其它更好的文档


第一章:前言

对于C语言,有人认为它已经落伍了.对于这个问题,仁者见仕,智者见智.的确,C++比C有更强大的诸多优势.但C++是建立在C之上的.这也是HerbertSchildt所著的<
你可以在forum.linuxaid.com.cn上获得此帖的文本.而其HTML版本正在赶制之中......如果你是在一个月之后看到本文,那么此文或许已经更新了:-)

第二章:约定

专业的源程书写风格.先看看世界级C大师的源程书写风格.如SteveMaguire就有许多不错的建议.

[]倡导使用易于理解的"匈牙利式"的命名约定.所有的字符变量均以ch开始;如:charch_****;所有的字节变量均冠以b;如:byteb_****;所有的长字变量均冠以l;如:longl_****;所有的指针变量均冠以P;如:char*p_ch_****;建议类型派生出的基本名字之后加上一个以大写字母开头的"标签".如:分析char**ppchMydata;其让人一眼就能看出它代表一个指向字符指针Mydata的指针."匈牙利式"命名的最大不足是难念:-((.但相对于不是总统演讲稿的C源程来说,这又算得了什么?想想看以下的数据命名:chara,b,c;longd,e,f;...(反正我是不会再看下去了...)

[]倡导规范书写.如果你思如泉涌,而不去也不及顾虑书写格式,那也没关系.在将其交出去之前,用cb命令格式化你的源程.虽然源程的格式不会影响到你编译结果的正确性,但切记,能让其他的程序员能轻松地阅读它.否则没人会理你的.关于cb命令的更多用法,可以用mancb来参考其手册页.当然除了cb之外,还有更多更好的.但cb是你在任何UNIX(LINUX)上都找得到的.更何况它并不差.

第三章:开始任务

开始任务之前,先做个深呼吸!

[]其他文档你准备好了吗?你是不是除了C源程之外一无所有了吗?兵马未动,粮草先行.你必须先清楚该程序所要完成的功能.在开始写程序之前,对程序的功能应有规范说明.书写规范书和确知程序功能的一个方法是先编写相应的操作手册.如果你是一人单干,劝你首先写需求书.切记切记,这对你意味着事半功倍的大好事.一个实例:我计划为本行的信贷子功能模块打一个补丁.我用10周的时间用来写规划书,需求书,操作流程,使用说明等等文档.之后用2周的时间编写程序,在初步测试(1周)后递交给各信贷部门测试使用.然后根据反馈的信息再更改相应文档,并根据文档修改源程.6个月后发布正式版.

[]一定该遵循ANSI标准吗?如果你仅使用ANSI的标准首标文件,恭喜你,你的程序有着全世界范围内的广泛支持和兼容.光明无限.但你必须在通用与专用之间做出取舍,对不起,我帮不了你.我的原则是:核心用ANSI,界面按需而取.这样在转换平台时仅需另编用户界面而已.实用至上嘛.附:ANSI标准C头文件


[]再续前缘?在得到新任务之后并在开始该新任务之前应马上回想有哪些是曾经拥有的.旧调重弹远比另起炉灶来的高效与环保.

[]是否该有自已的库?我的答案是应该有自已的特色库,并与ANSI兼容.与3.8不同的是,你仅需在源程序之后附上自已的专用库就可以了.其次在有了自已的库后,源码会很精炼的.不用去羡慕别人了吧.

[]要学会条件编译.注意你的平台特性.(高手的标志?)除非你确定你要写的程序是在某特定的OS特定的硬件平台而量身定做.否则应注意数据类型的长度,精度都是不同的,不要想当然.有时甚至是不同的编译器的差异都要考虑考虑.

........(欢迎您来充实此处空白)....

好了,在任务中,又有哪些细节呢?

[]我是不是葛郎台?不要那么吝啬.在源程序中加入详尽的注释以使自己和他人即使在许多年以后仍能读明白它是什么样的程序.用注释行分离各个函数.

[]删除不需要的代码时要小心.一个好建议是:使用#ifdefDEL,而不是简单地注释掉甚至是粗暴地直接dd.如果你是使用/*...*/,但一旦要删除的代码有很多行,或注释中以有注释时,这就可能不那么好使了.

[]如何给源程序文件命名?表现特色且不与任何原有应用名相同.一个简单地方法就是试试看,系统有什么样地反应?

[]一次只修改一个地方.

[]一次只编写一个单一功能的函数。

[]编写通用程序.只有当程序编写完,并且完成了所需要的性能要求之后,再反过头来优化该程序.

[]不要使用a.out作为结果.你大可以使用与源程相同的可执行文件名.

[]是否一定要用VI编辑?LINUX下有许多专用编程编辑器.它们能使你有更高的效率和更低的低级输入错误,但我还是要劝你至少要熟练掌握VI.毕竟VI遍地开花.

[]协同作业.请相信,你不是在孤军作战.因此,你有必要熟练掌握一些其它的工具.如

........(欢迎您来充实此处空白)....

第四章:使用lint

lint没有你想象中的那样糟糕.相反,一旦源程序形成了没有LINT错误的形式,将很容易保持下去,并享受到如此而带来的好处.

[]在cc(gcc)之前就应使用LINT.lint是一语法检查程序,对于这个多嘴的婆婆来说,你应有足够的耐心.虽然你知道自已在干什么,但在CC之前使用LINT总是一个好习惯.

[]lint有哪些特色?在编译之前使用lint的重要原因是LINT不但能发现ANSIC中的语法错误,而且也能指出潜在的问题或是难于移植于另一机器的代码问题.除了能指出简单语法错误之外,LINUT还能基于以下原因指出另外的错误:A.无法达到的语句.B.没有进入循环.C.没有被使用的变量.D.函数参数从未使用.E.没有赋值之前自动使用参数.F.函数在有些地方有返回值,但在其他地方不返回.G.函数调用在不同地方使得参数个数不同.H.错误使用结构指针.I.模糊使用操作符优先级.呵呵呵,挺有用的吧!

[]如何控制LINT的输出?有时LINT会有一大屏一大屏的警告信息.但似乎并未指出错误.为了找出潜在的错误则需费心费力地浏览这些大量的警告信息.但如果你的程序会分出几个独立的模块,在初级启动LINT时不要用可选项.当对这些模块进行更改或扩充时,可以忽略与代码无关的某些警告.为此可用以下选择项:-h对判别是否有错,类型是否正确不给出启发式测试.-v不管函数中没有定义的参数-u不管被使用的变量和函数没有定义或定义了但没有使用.

[]干脆,在程序中插入指令来影响LINT运行.它看样子有些像注释./*NOTREACHED*/不可达到的代码不给信息说明./*VARARGSn*/函数的变量个数不作通常的检查,只检查开始n个参数的数据类型./*NOSTRUCT*/对下一个表达式不作严格类型检查./*ARGUSED*/下一函数中,不给出没被使用参数的警告信息./*LINTLIBRARY*/置于文件的开头,它将不给出没被使用函数的警告信息.

关于LINT的更多用法,请用manlint来获知.

第五章:使用make

[]什么是make?

Unix(Linux)是一个天生的开发平台,我为此感到高兴.make是一个强力的工具.它能自动跟踪相互依赖的源代码块并组成一程序,使得很容易建立一可执行程序.Make就是这种有依赖关系的部分和代码之间所作的规格说明.

[]所有的程序都要使用make?是的.尽管你只有几个简单的模块,但你需要有一种结构来支持它从简单走向复杂.除非你的程序已经盖棺定论.

[]Makefile由哪些组成?Makefile由以下几个部分组成:

注释.^^^^使用#符号插入.make将忽略#之后的任何内容以及其后的RETURN键.

变量.^^^^make允许定义与SHELL变量类似的有名变量.比如,你定义了SOURCES=prog.c,那么该变量的值$(SCOURES)就包含了源文件名.

依赖关系.^^^^^^^^左边是目标模块,后接一冒号.再接与该模块有依赖关系的模块.

命令.^^^^以TAB键开始(即使用相同数量的空格也不能代替它).

[]Makefile示例下面介绍一个简单的示例来说明make的用法.假设你的程序有两个源文件main.c和myc.c,一个位於子目录include下的头文件myhead.h,一个库由三个源文件myrout1.c,myrout2.c,myrout3.c产生.其makefile文件为:#一个基本的MAKEFILE文件.#其中包括个人的头文件和个人库.HEADERS=include/myhead.hSOURCES=main.cmyc.cPRODUCT=$(HOME)/bin/toolLIB=myrout.aLIBSOURES=myrout1.cmyrout2.cmyrout3.cCC=ccCFLAGS=-gall:$(PRODUCT)$(PRODUCT):$(SOURCES)$(CC)$(CFLAGS)-o$(PRODUCT)$(SOURCES)lint:$(PRODUCT)lint$(SOURCES)$(LIBSOURCES)哈哈,挺象SHELL编程的.如果你与我一样使用LINUX下的gcc,那么只要把上面的CC=cc改为CC=gcc即可.怎么样,想来一个更复杂点的吗?

[]一个更为复杂的Makefile你是否注意到,在上例中,只要启动make,就会重新编译所有源代码.如果你能看懂以下的makefile,恭喜恭喜,你通关了.#一个更为复杂的makefileHEADERS=include/myhead.hSOURES=main.cmyc.cOBJECTS=main.cmyc.cPRODUCT=$(HOME)/bin/toolLIB=myrout.aLIBSOURCES=myrout1.cmyrout2.cmyrout3.cLIBOBJECTS=$(LIB)(myrout1.o)$(LIB)(myrout2.o)$(LIB)(myrout3.o)INCLUDE=includeCC=ccCFLAGS=-g-XcLINT=lintLINTFLAGS=-Xcall:$(PRODUCT)$(PRODUCT):$(OBJECTS)$(LIB)$(CC)(CFLAGS)-o$(PRODUCT)$(OBJECTS)$(LIB).c.o:$(HEADERS)$(CC)$(CFLAGS)-cI$(INCLUDE)$<$(LIB):$(HEADERS)$(LIBSOURCES)$(CC)$(CFLAGS)-c$(?:.o=.c)arrv$(LIB)$?rm$?.c.c:;lint:$(PRODUCT)$(LINT)$(LINIFLAGS)$(SOURCES)$LIBSOURCES)

第六章:优质无错编程

亲爱的,检查一下,你是否注意到了以下的细节?也就是说,你是否是一个合格的,能编写优质无错代码的程序员?要永远记住,编写无错代码是程序员的责任,而不是测试员.(摘录于本人的"细节页",因此本节将永远不会保持完整,欢迎您来充实她)

[]所有程序员至少出现过的一个错误:if(a=3){......}如果a等于3,那么......你至少要养成这样的习惯:当判断一个变量与一个常量是否相等时,将常量写在前面.这样即使你一不小心写成这样:if(3=a){......}在cc之前就可以很容易发现它.

[]老调重弹:逻辑操作符的优先权.我不愿多嘴.总之,如果你一定要编写如下代码时:if(a&0x1&&b&0x2){......}你的手头最好有一本详尽的指南.或者你是这方面的专家.

[]尽量不使用int数据类型.这仅是一个忠告.你大可使用char,short,long数据类型.若干年以后,当你成长为高手之时,你会发现此时我的良苦用心.

[]对于非整型函数一定要完整定义.如longfloatjisuan(charchArr[],intchNum){longfloatlMydata;......return(lMydata);}

[]对于非整型函数的输入要当心.如longfloatlfNum;......scanf("%lf",&lfNum);

[]float型的有效数字为7位.当多于7位时,第8位及以后的位将不准确,可以将其定义为longfloat型.

[]文件的输入出尽量采用freadfwrite函数.只有当另有用途时才用fprintffscanf函数.

[]对于数组及字符串的比较操作时要确认以\结束.

第七章:调试技术

调试技术在本文中不太好说,之所以将其独立成章是想套用M$的老话:"在下一版本中将会做得更好":-((.其实这类文章在全国各大BBS上满天飞.

在此我只想说说程序员的应尽职责之一:在程序中使用断言.~~~~[]既要维护程序的交付版本,又要维护程序的调试版本,这时可以利用断言补救.

[]要使用断言对函数参数进行确认.

[]要从程序中删除无定义的特性,或者在程序中使用断言来检查出无定义特性的非法使用.

[]不要浪费别人的时间,详细说明不清楚的断言.

[]消除所做的隐式假定,或者利用断言检查其正确性.

[]利用断言来检查不可能发生的情况.

- 作者: xiaohuar 2005年01月2日, 星期日 10:24  回复(0) |  引用(0) 加入博采

Apache+TOMCAT+JSP整和

 Apache和Tomcat连接的方法大致有JK1.x, JK2, mod_webapp三种connector可以使用,下面简单说明一下
  Apache2.0.50 + Tomcat5.0.29 + mod_jk2的连接方法,环境为windows XP

1、下载:
       apache2.0.50从http://apache.org下载
       tomcat5.0.28从http://jakarta.apache.org下载
       module_jk2从http://jakarta.apache.org下载


2
      Apache到D:\Apache Group\Apache2
      Tomcat到E:\work\jakarta-tomcat-5.0.28
      module文件为jakarta-tomcat-connectors-jk2.0.4-win32-apache2.0.49.zip 解压缩,将modules/mod_jk2.so拷贝到
     D:\Apache Group\Apache2\modules下,conf/workers2.properties.sample拷贝到D:\Apache Group\Apache2\conf下,
     并改名为worker1.properties
3、修改D:\Apache Group\Apache2\conf\httpd.conf,增加
     LoadModule jk2_module "modules/mod_jk2.so"
     JkSet config.file "conf/workers2.properties"
   
    Apache配置完毕,重新启动Apache
4、tomcat默认支持ajp1.3的jk2连接,所以只需要配置apache就可以,剩下的就是将需要访问的目录增加到
     worker2.properties就可以了,默认为
[shm]
info=Scoreboard. Requried for reconfiguration and status with multiprocess servers.
file=anon

# Defines a load balancer named lb. Use even if you only have one machine.
[lb:lb]

# Example socket channel, override port and host.
[channel.socket:localhost:8009]
port=8009
host=127.0.0.1

# define the worker
[ajp13:localhost:8009]
channel=channel.socket:localhost:8009
group=lb

# Map the Tomcat examples webapp to the Web server uri space
[uri:/examples/*]
group=lb

[status:]
info=Status worker, displays runtime information

[uri:/jkstatus/*]
info=The Tomcat /jkstatus handler
group=status:
[shm]
info=Scoreboard. Requried for reconfiguration and status with multiprocess servers.
file=D:/Apache Group/Apache2/logs/jk2.shm
size=1048576

需要修改一下apache的默认目录,然后我增加了两个目录/servlets-examples和/axis,得到如下

# Defines a load balancer named lb. Use even if you only have one machine.
[lb:lb]

# Example socket channel, override port and host.
[channel.socket:localhost:8009]
port=8009
host=localhost

# define the worker
[ajp13:localhost:8009]
channel=channel.socket:localhost:8009
group=lb

# Map the Tomcat examples webapp to the Web server uri space
[uri:/jsp-examples/*]
group=lb
[uri:/bbs/*]
group=lb
[uri:/servlets-examples/*]
group=lb
[uri:/axis/*]
group=lb
[status:]
info=Status worker, displays runtime information

[uri:/jkstatus/*]
info=The Tomcat /jkstatus handler
group=status:

[uri:/*.jsp]
worker=ajp13:localhost:8009
    
重新启动apache,tomcat
访问
http://localhost/jkstatus/
http://localhost/servlets-examples/
http://localhost/axis/
http://localhost:8080/servlets-examples/
http://localhost:8080/axis
看一下结果,如果还要增加新的目录,只要照上面操作即可


 

- 作者: xiaohuar 2005年01月2日, 星期日 10:23  回复(3) |  引用(0) 加入博采

Exceed PHP - 正则表达式中的特殊字符


字符/
意义:对于字符,通常表示按字面意义,指出接着的字符为特殊字符,不作解释。
例如:/b/匹配字符'b',通过在b 前面加一个反斜杠,也就是/b/,则该字符变成特殊字符,表示
匹配一个单词的分界线。
或者:
对于几个字符,通常说明是特殊的,指出紧接着的字符不是特殊的,而应该按字面解释。
例如:*是一个特殊字符,匹配任意个字符(包括0个字符);例如:/a*/意味匹配0个或多个a。为了匹配字面上的*,在a前面加一个反斜杠;例如:/a*/匹配'a*'。

字符^
意义:表示匹配的字符必须在最前边。
例如:/^A/不匹配"an A,"中的'A',但匹配"An A."中最前面的'A'。

字符$
意义:与^类似,匹配最末的字符。
例如:/t$/不匹配"eater"中的't',但匹配"eat"中的't'。

字符*
意义:匹配*前面的字符0次或n次。
例如:/bo*/匹配"A ghost booooed"中的'boooo'或"A bird warbled"中的'b',但不匹配"Agoat g
runted"中的任何字符。

字符+
意义:匹配+号前面的字符1次或n次。等价于{1,}。
例如:/a+/匹配"candy"中的'a'和"caaaaaaandy."中的所有'a'。

字符?
意义:匹配?前面的字符0次或1次。
例如:/e?le?/匹配"angel"中的'el'和"angle."中的'le'。

字符.
意义:(小数点)匹配除换行符外的所有单个的字符。
例如:/.n/匹配"nay, an apple is on the tree"中的'an'和'on',但不匹配'nay'。


字符(x)
意义:匹配'x'并记录匹配的值。
例如:/(foo)/匹配和记录"foo bar."中的'foo'。匹配子串能被结果数组中的素[1], ...,[n] 返
回,或被RegExp对象的属性, ..., 返回。

字符x│y
意义:匹配'x'或者'y'。
例如:/green│red/匹配"green apple"中的'green'和"red apple."中的'red'。

字符{ n }
意义:这里的n是一个正整数。匹配前面的n个字符。
例如:/a{ 2 }/不匹配"candy,"中的'a',但匹配"caandy," 中的所有'a'和"caaandy."中前面的两个'a'。

字符{ n, }
意义:这里的n是一个正整数。匹配至少n个前面的字符。
例如:/a{ 2, }不匹配"candy"中的'a',但匹配"caandy"中的所有'a'和"caaaaaaandy."中的所有'a'
 
 



字符{ n,m }
意义:这里的n和m都是正整数。匹配至少n个最多m个前面的字符。
例如:/a{ 1,3 }/不匹配"cndy"中的任何字符,但匹配 "candy,"中的'a',"caandy," 中的前面两个
'a'和"caaaaaaandy"中前面的三个'a',注意:即使"caaaaaaandy" 中有很多个'a',但只匹配前面的三 个'a'即"aaa"。

字符[xyz]
意义:一字符列表,匹配列出中的任一字符。你可以通过连字符-指出一个字符范围。
例如:[abcd]跟[a-c]一样。它们匹配"brisket"中的'b'和"ache"中的'c'。

字符[^xyz]
意义:一字符补集,也就是说,它匹配除了列出的字符外的所有东西。 你可以使用连字符-指出一 字符范围。
例如:[^abc]和[^a-c]等价,它们最早匹配"brisket"中的'r'和"chop."中的'h'。

字符
意义:匹配一个空格(不要与b混淆)

字符b
意义:匹配一个单词的分界线,比如一个空格(不要与混淆)
例如:/bnw/匹配"noonday"中的'no',/wyb/匹配"possibly yesterday."中的'ly'。

字符B
意义:匹配一个单词的非分界线
例如:/wBn/匹配"noonday"中的'on',/yBw/匹配"possibly yesterday."中的'ye'。

字符cX
意义:这里的X是一个控制字符。匹配一个字符串的控制字符。
例如:/cM/匹配一个字符串中的control-M。

字符d
意义:匹配一个数字,等价于[0-9]。
例如:/d/或/[0-9]/匹配"B2 is the suite number."中的'2'。

字符D
意义:匹配任何的非数字,等价于[^0-9]。
例如:/D/或/[^0-9]/匹配"B2 is the suite number."中的'B'。

字符f
意义:匹配一个表单符

字符n
意义:匹配一个换行符

字符r
意义:匹配一个回车符

字符s
意义:匹配一个单个white空格符,包括空格,tab,form feed,换行符,等价于[ fnrtv]。
例如:/sw*/匹配"foo bar."中的' bar'。

字符S
意义:匹配除white空格符以外的一个单个的字符,等价于[^ fnrtv]。
例如:/S/w*匹配"foo bar."中的'foo'。

字符t
意义:匹配一个制表符

字符v
意义:匹配一个顶头制表符

字符w
意义:匹配所有的数字和字母以及下划线,等价于[A-Za-z0-9_]。
例如:/w/匹配"apple,"中的'a',".28,"中的'5'和"3D."中的'3'。

字符W
意义:匹配除数字、字母外及下划线外的其它字符,等价于[^A-Za-z0-9_]。
例如:/W/或者/[^$A-Za-z0-9_]/匹配"50%."中的'%'。

字符n
意义:这里的n是一个正整数。匹配一个正则表达式的最后一个子串的n的值(计数左圆括号)。

例如:/apple(,)sorange1/匹配"apple, orange, cherry, peach."中的'apple, orange',下面有一个更加完整的例子。
注意:如果左圆括号中的数字比n指定的数字还小,则n取下一行的八进制escape作为描述。

字符ooctal和xhex
意义:这里的ooctal是一个八进制的escape值,而xhex是一个十六进制的escape值,允许在一个正则表达式中嵌入ASCII码

附:下表是元字符及其在正则表达式上下文中的行为的一个完整列表:

字符 描述 
\
将下一个字符标记为一个特殊字符、或一个原义字符、或一个后向引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\' 匹配 "" 而 "\(" 则匹配 "("。
^
匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。
$
匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。
*
匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。 * 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
?
匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。
{n}
n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
{n,}
n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
{n,m}
m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。刘, "o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。
?
当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。
. 
匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。
(pattern)
匹配pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 {CONTENT}... 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。
(?:pattern)
匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。
(?=pattern)
正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如, 'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?!pattern)
负向预查,在任何不匹配Negative lookahead matches the search string at any point where a string not matching pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始
x|y 
匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。
[xyz]
字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。
[^xyz]
负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'。
[a-z]
字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。
[^a-z]
负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。
\b
匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B
匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
\cx
匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。 x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。
\d
匹配一个数字字符。等价于 [0-9]。
\D
匹配一个非数字字符。等价于 [^0-9]。
\f
匹配一个换页符。等价于 \x0c 和 \cL。
\n
匹配一个换行符。等价于 \x0a 和 \cJ。
\r
匹配一个回车符。等价于 \x0d 和 \cM。
\s
匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S
匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t
匹配一个制表符。等价于 \x09 和 \cI。
\v
匹配一个垂直制表符。等价于 \x0b 和 \cK。
\w
匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。
\W
匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。
\xn
匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如, '\x41' 匹配 "A"。'\x041' 则等价于 '\x04' & "1"。正则表达式中可以使用 ASCII 编码。.
\num
匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)' 匹配两个连续的相同字符。
\n
标识一个八进制转义值或一个后向引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为后向引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。
\nm
标识一个八进制转义值或一个后向引用。如果 \nm 之前至少有is preceded by at least nm 个获取得子表达式,则 nm 为后向引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的后向引用。如果前面的条件都不满足,若  n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。
\nml
如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。
\un
匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如,\u00A9 匹配版权符号 (?)。

- 作者: xiaohuar 2004年12月20日, 星期一 07:54  回复(1) |  引用(0) 加入博采

Apache指南:服务器端包含入门

服务器端包含提供了一种对现有HTML文档增加动态内容的方法。

本文针对服务器端包含(Server Side Includes),通常简称为SSI,讨论如何配置服务器以允许SSI,并介绍一些对现有HTML页面增加动态内容的基本SSI技术。

本文后部将讨论用SSI做一些应该算比较高级的事情,比如SSI指令中的条件语句。


什么是SSI?
SSI (Server Side Includes)是HTML页面中的指令,在页面被提供时由服务器进行运算,以对现有HTML页面增加动态生成的内容,而无须通过CGI程序提供其整个页面,或者使用其他动态技术。

对什么时候用SSI,而什么时候用某些程序生成整个页面的权衡,取决于页面中有多少内容是静态,有多少内容需要在每次页面被提供时重新计算。SSI是一种增加小段信息的好方法,诸如当前时间。如果你的页面大部分是在被提供时生成的,那就要另找方案了。


配置服务器以允许SSI
要使服务器允许SSI,必须在httpd.conf文件或.htaccess文件中有如下配置:

Options +Includes

告诉服务器以允许解析文件中的SSI指令。注意,在多数配置中,多个Options指令会互相覆盖,所以,可能必须对需要SSI的特定目录使用Options,以确保位于最后并起作用。

并不是所有文件中的SSI指令都会被解析,所以,必须告诉Apache应该解析哪些文件。有两种方法,使Apache解析带有特定文件后缀的任何文件,比如.shtml, 配置如下:

AddType text/html .shtml
AddOutputFilter INCLUDES .shtml

这种方法的缺点之一是,为了使文件名有.shtml后缀从而执行其中的指令,可能需要改变加入SSI指令的现有的文件,以及所有指向此页面的连接。

另一种方法是,使用XBitHack指令:

XBitHack on

XBitHack告诉Apache解析有执行权限的文件中的SSI指令。如此,只要用chmod使文件变成可执行的,就可以对现有的页面增加SSI指令。

chmod +x pagename.html

这里简要说明一点:偶然会有人向你推荐,无须用带.shtml的文件名,使Apache解析所有.html文件的SSI就可以了。那些人可能没听说过XBitHack。要知道,这样做会使Apache在发送文件到客户端之前通读此文件,即使其中并没有任何SSI指令,从而对速度有不小影响,所以这并不是好办法。

当然,在Windows上,没有对应的执行权限可以设置,但还是应该谨慎选择。

按缺省配置,Apache不会为SSI页面发送最后修改日期或者内容长度的HTTP头,因为这些值对动态页面来说难以计算。这样会阻止页面被缓冲,导致客户端性能有能够感觉到的下降。有两种解决方法:

使用XBitHack Full配置。它告诉Apache判断最后修改日期时,只查看被请求的文件本身的日期,而忽略其中包含的任何文件的修改日期。
使用mod_expires提供的指令为文件设置一个明确的过期时间,并告诉浏览器和代理这个文件可以被缓冲。

基本SSI指令
SSI指令有如下语法:

<!--#element attribute=value attribute=value ... -->

其格式很象HTML的注释,因此如果没有正确配置SSI,它会被浏览器忽略,但在HTML代码中仍然可见。而如果正确配置了SSI,则此指令会被其结果替代。

其中的元素可以有许多,我们会在下一个版本的文档中讨论其中的大多数,而在这里,仅举几个SSI的例子。

今天的日期
<!--#echo var="DATE_LOCAL" -->

echo元素仅仅是反馈一个变量的值。标准变量有许多,其中包含对CGI程序有效的所有的环境变量。另外,你也可以用set元素定义你的专用变量。

如果你不喜欢日期的这种打印格式,可以用config元素的timefmt属性,改变其格式。

<!--#config timefmt="%A %B %d, %Y" -->
Today is <!--#echo var="DATE_LOCAL" -->

文件的修改日期
This document last modified <!--#flastmod file="index.html" -->

这个元素也是使用timefmt的格式配置。

包含一个CGI程序的输出
这是SSI的很常见的一个用途-包含一个CGI程序的输出,比如人人喜欢的``点击计数器''。

<!--#include virtual="/cgi-bin/counter.pl" -->


附加的例子
以下是一些对HTML文档使用SSI的特殊例子。

文档是什么时候被修改的?
此前,我们提到过可以用SSI通知用户文档是什么时候被修改的,但是其具体实施方法却基本上是个问题。以下代码,放在HTML文档中,会在页面中产生一个时间戳,当然,首先,你必须按上述方法使SSI有效。

<!--#config timefmt="%A %B %d, %Y" -->
This file last modified <!--#flastmod file="ssi.shtml" -->

不用说,你应该用你实际引用的文件名来替换ssi.shtml,所以,如果你想简单地在任何文件中粘贴一段通用代码以达到这个目的,这个方法就并不方便,如此,就会用到LAST_MODIFIED变量:

<!--#config timefmt="%D" -->
This file last modified <!--#echo var="LAST_MODIFIED" -->

有关timefmt格式的细节,可以到搜索站点查找strftime,其语法是相同的。

包含一个标准注脚
如果你管理一个拥有许多页面的站点,你会发现对所有页面做改动是很痛苦的,尤其是在试图对所有页面维持某种标准观感的时候。

使用包含一个页眉和/或注脚的方法,可以减轻修改的负担。你只要制作一个注脚文件,并用includeSSI命令包含到每个页面,即可。include元素能按file属性或者virtual属性判断应该包含的文件。file属性是一个相对于当前目录的文件路径,即不能是一个绝对文件路径(以/开头)。virtual属性可能更有用,它是一个相对于被提供文档的URL,可以以/开头,但必须与被提供文档在同一个服务器。

<!--#include virtual="/footer.html" -->


SSI指令和注脚文件相结合使用是很有用的,比如在注脚文件中使用LAST_MODIFIED指令。SSI指令可以出现在包含文件中,而include可以嵌套,即一个包含文件可以包含另一个。


其他的设置
config除了能设置时间格式,还有两种用途。

当SSI指令发生错误时,会产生如下消息:

[an error occurred while processing this directive]

为了改变消息的形式,可以使用config元素的errmsg属性:

<!--#config errmsg="[It appears that you don't know how to use SSI]" -->

当然,最终用户永远也不会看到这个消息,因为在网站投入运行之前你已经把这些问题都解决了(是吗?)。

还可以使用config的sizefmt属性设置返回的文件大小的格式,或者是以字节为单位,或者是以Kb或Mb为单位的简写。


执行命令
我期望未来几个月内能再写一篇小型CGI程序使用SSI的文章,而这里,仅介绍exec的使用。SSI确实可以利用shell(/bin/sh,精确地说,还可以是Win32中的DOS shell)来执行命令。下例产生一个目录列表:

<pre>
<!--#exec cmd="ls" -->
</pre>

在Windows中:

<pre>
<!--#exec cmd="dir" -->
</pre>

你可能会发现,在Windows中这个指令的结果有些奇怪,dir的输出中包含有字串``<dir>'',它会使浏览器产生混淆。

注意,这个功能是极度危险的,因为它会执行任何包含在exec标记中的命令。如果用户有可能修改你的网页内容,比如"留言本",那么你一定要关闭这个功能。在Options指令中加上IncludesNOEXEC参数,以关闭exec功能,同时又保留SSI。


高级SSI技术
除了分离内容,Apache SSI还可以设置用以比较和条件表达式的变量。

警告
本文中讨论的大多数功能仅在Apache 1.2及更新版本中有效。如果你运行的不是Apache 1.2及更新版本,请立刻或者尽快升级,现在就动手,我们会等你弄好了再继续往下讲。

设置变量
使用set指令可以设置变量以备后用,其语法是:

<!--#set var="name" value="Rich" -->

除了设置文字变量以外,还可以设置其他任何变量,比如环境变量和此前提到过的一些变量(如LAST_MODIFIED),作为你的专用变量。在变量名前面缀以$,表示它是一个变量,而不是一个文字性字串。

<!--#set var="modified" value="$LAST_MODIFIED" -->

在文字性字串中使用$,必须使用转义符号\

<!--#set var="cost" value="\$100" -->

最后,如果要在较长的字串中,可以用花括号把变量名括起来,以免变量名与其他字符之间冲突而产生混淆(要对这种情况举例说明有点难度,但还是希望你能领会)。

<!--#set var="date" value="${DATE_LOCAL}_${DATE_GMT}" -->

条件表达式
有了变量,就可以设置和比较它们的值以表示条件,SSI也因此成为一种简洁的编程语言。mod_include提供了if, elif, else和endif等结构以构造条件语句,从而对一个实在的页面高效地生成多个逻辑的页面。

条件的结构如下:

<!--#if expr="test_condition" -->
<!--#elif expr="test_condition" -->
<!--#else -->
<!--#endif -->

test_condition可以是任何逻辑比较 - 可以是一个值和另一个值比较,也可以是测试一个特定的值是否为"真"(一个给定的字串如果非空则为真)。完整的比较操作符列表,见mod_include。以下是可能会用到的一些例子。

在配置文件中,可以这样设置:

BrowserMatchNoCase macintosh Mac
BrowserMatchNoCase MSIE InternetExplorer

如果客户端在Macintosh上运行Internet Explorer,则上例设置环境变量``Mac'' 和``InternetExplorer''为真。

然后,在允许SSI的文档中,可以这样设置:

<!--#if expr="${Mac} && ${InternetExplorer}" -->
Apologetic text goes here
<!--#else -->
Cool JavaScript code goes here
<!--#endif -->

我一点也不反对在Mac上运行IE - 只是上个星期我花了好几个小时试图在Mac上的IE中使用JavaScript,而它在其他地方都能正常运作,以上只是一个临时的妥协方案。

任何其他变量(或者是你定义的,或者是标准的环境变量)都可以用于条件语句。利用Apache的SetEnvIf以及其他相关指令设置环境变量,此功能可以很好地实现动态页面而无须借助于CGI。


总结
SSI固然不能替代CGI或者其他动态页面技术,但它是在页面中插入众多小型的动态片段的优秀方法,而无须大量额外的操作。

 

- 作者: xiaohuar 2004年12月6日, 星期一 13:09  回复(0) |  引用(0) 加入博采