PSV内容管理助手复制到电脑里的psv游戏回收带不带

ISAPI_Rewrite 3.1 教程中文版(13)-源码库|专注为中国站长提供免费商业网站源码下载!
当前位置:---ISAPI_Rewrite 3.1 教程中文版(13)
ISAPI_Rewrite 3.1 教程中文版(13)
server config, virtual host, directory, .htaccess
&File&指令以文件名限定了封装的指令的作用域。filename参数必须包含一个文件名,支持?和*以及以~字符打头的正则表达式。示例:&Files index.*&
# ... directives here ... &/Files&&Files ~ "\.(gif|jpe?g|png)$"&
# ... directives here ... &/Files&
不要忘了在每个&Files&标签中包含RewriteEngine on指令,也不要将不能应用的规则封装进去。
4.20&FilesMatch&指令
将应用于匹配文件名的指令包装起来
&FilesMatch regex& ... &/FilesMatch&
server config, virtual host, directory, .htaccess
&FilesMatch&指令的语法和_指令"&&Files ~&语法完全一样。&FilesMatch "\.(gif|jpe?g|png)$"&
不要忘了在每个&FilesMatch&标签中包含RewriteEngine on指令,也不要将不能应用的规则封装进去。
4.21&Location&指令
把被包装起来的指令集应用到匹配的URL或者虚拟路径
&Location URL-path|URL& ... &/Location&
server config, virtual host
&Location& ... &/Location&标签用来将应用到特定URL或者虚拟路径的指令分组。&Location&将运算符完全从文件系统中分划出来,因此那些指令将不会用来控制对文件文件系统位置的访问。因为有几个不同的URL可能映射到相同的文件系统位置。该URL-path是一个形式为“/path/”的虚拟路径。没有协议、主机名、端口号、查询请求字符串被包含在内。URL-path可以包含通配符?和*或者以~字符打头的正则表达式。示例:&Location /directory& # ... rules go here&/Location&&Location /&
# ... more rules go here&/Location&
不要忘了在每个&Location&标签中包含RewriteEngine on指令,也不要将不需要用到的规则封套进去。
4.22&LocationMatch&指令
把被包装起来的指令集应用到正则表达式匹配的URL上
&LocationMatch regex& ... &/LocationMatch&
server config, virtual host
这个指令的语法和指令"&&Location ~&正则表达式语法完全一样。示例:&LocationMatch "/(home|section)/bin"&
# ... rules go here&/LocationMatch&
不要忘了在每个&LocationMatch&标签中包含RewriteEngine on指令,也不要将不能应用的规则封装进去。
注意:这些示例中所有的规则只适用于httpd.conf文件。在ISAPI_Rewrite以及在Apache的mod_rewrite中,规则的基本路径是不同的,取决于你放置.htaccess文件的目录。如果你将规则放在httpd.conf里的话,初始领头斜线必须存在,而在.htaccess文件中,到这些文件的虚拟路径会被截断。规则取决于以RewriteBase /指令引导的根路径,来允许它们在httpd.conf和目录级的.htaccess文件的任何位置上运作。简单的搜索引擎友好的网址下面这个例子演示了如何轻松地使用循环标记藏匿查询字符串参数。假设你有一个如下的URL:?a=A&b=B&c=C,而且你希望以这样的地址来访问它:请尝试用下面的规则来达到预期的效果:RewriteEngine onRewriteRule ^(.*?\.asp)/([^/]*)/([^/]*)(/.+)? $1$4?$2=$3 [NC,LP,QSA]注意这个规则可能破坏页面与CSS文件、图片等的相对链接。至所以这样是因为在浏览器中用于推算完整资源URI的基本路径(页面的父文件夹)发生了变化。只有在您使用目录分隔符作为替代字符时才会发生这个问题。有三种可用的解决方案:1.使用下面的规则,它不影响基本路径,因为它没有用到目录分隔符“/”。2.借助于&base href="/folder/"&标签直接为页面指定正确的base路径3.把所有的页面相对链接都变成相对于根目录的地址或者绝对地址形式。还存在着很多种用了不同的分隔符和文件扩展名的规则。例如,使用像这样的URL:~a~A~b~B~c~C。下面的规则可以用来实现它:RewriteEngine onRewriteRule ^(.*?\.asp)~([^~]*)~([^~]*)(.*) $1$4?$2=$3 [NC,LP,QSA]富关键词URLs在上面的例子中,我们使用很一般的技术来简单地藏匿查询字符串标记。但是很多对搜索引擎优化很有用的解决方案是让您的URL关键字丰富。看看下面的网址,例如:?productID=127这是大部分网站的常见情况。但是你可以通过使用这样形式的链接来显著地提高你的网页搜索引擎抓取率:,URL中的关键词“our super tool”会被索引,并提高网页排名,但是“our_super_tool”不能直接被用来收回productid=127,这个问题存在几种解决方案。第一个解决方案,我们建议你使用简短、只包含少数几个参数(既有关键词也有数字标识符)的URL形式,在样您的URL可能看起来如下:。实现这一重写目标只需要一个规则:RewriteEngine onRewriteBase /RewriteRule ^products/[^?/]*_(\d+)\.asp /productpage.asp?productID=$1 [QSA]
另一个更复杂的解决方案是创建一对一的映射文件,并用它来映射“our_super_tool”到127。该解决方案对一些有很多参数的长URL来说很有用,并允许你隐藏数字标识符。这URL看起来像是。请注意“our_supper_tool”部分必须是产品的唯一标识,是它的标识符。下面是这种解决方案的一个示例:RewriteEngine onRewriteBase /RewriteMap mapfile txt:mapfile.txtRewriteRule ^products/([^?/]+)\.asp /productpage.asp?productID=${mapfile:$1}
而且你必需创建包含以下内容的mapfile.txt映射文件:one_product
1another_product
2our_super_tool
127more_products
这种方法的优点是:你可以使用它来组合十分复杂的URL转换,但是这是一个小例子,是这个指南中的题外之话。使用IIS作为反向代理 假设你有运行IIS的互联网服务器以及几台后台服务器或者应用程序运行在其它平台或者机器上。这些服务器不能直接在互联网上阅览,但是你必须为他人提供访问这些服务器的渠道。这里有一个演示如何简单地将某个网站的完整内容映射到另一个运行了ISAPI_Rewrite的站点的文件夹的示例:RewriteEngine onRewriteBase / RewriteRule mappoint(.+) $1 [NC,P]
藏匿文件扩展名: 虽然不可能将一个站点的所有的文件的扩展名都藏匿起来,但是我们可以使用ISAPI_Rewrite的文件检查功能来隐藏某些已知扩展名。这里有一个藏匿网站上.asp文件扩展名的规则示例:RewriteEngine on#Redirect extension requests to avoid duplicate contentRewriteRule ^([^?]+)\.asp$ $1 [NC,R=301,L]#Internally add extensions to requestRewriteCond %{REQUEST_FILENAME}.asp -f RewriteRule (.*) $1.asp
仿真基于主机头的虚拟网站 例如你已经注册了两个域名和。现在你可以使用同一个物理站创建两个不同的站点了。这里是一个规则示例:RewriteEngine on#Fix missing trailing slash char on foldersRewriteRule ^([^.?]+[^.?/])$ $1/ [R,L]#Emulate site1RewriteCond %{HTTP:Host} ^(?:www\.)?site1\.com$RewriteRule (.*) /site1$1 [NC,L,NS]#Emulate site2RewriteCond %{HTTP:Host} ^(?:www\.)?site2\.com$RewriteRule (.*) /site2$1 [NC,L,NS]
现在只要把你的站点分别放到/site1和/site2目录下就可以了。注意和这两个域名必须在IIS中被映射到这个网站里,从而使ISAPI_Rewrite能拦截到请求。或者,你可以使用更多通用的规则,从而把任何请求都映射到与请求主机名同名的文件夹里。RewriteEngine on#Fix missing trailing slash char on foldersRewriteRule ^([^.?]+[^.?/])$ $1/ [R,L]#Map requests to the foldersRewriteCond %{HTTP:Host} ^(www\.)?(.+)RewriteRule (.*) /%2$1 [NS]
网站的目录名应该是这样子的:/,/,等等。阻断内联图像(阻止盗链) 假如你有一些页面插入了下的gif图片。一些其它站点将通过网页超链接插入这些图片。这会给你的网站增加很多无用的通讯量,而且你希望阻止这种做法。虽然用ISAPI_Rewrite不能100%地保护图片不被盗链(只有专门的反盗链产品才能做到它),你至少可以在浏览器发来HTTP引用头的时候限制这种情况。下面的规则可以让你只允许来自同一主机的引用页或者空地址访问到这些图片。RewriteEngine onRewriteCond %{HTTP:Host}#%{HTTP:Referer} ^([^#]+)#(?!\1).+RewriteRule .*\.(?:gif|jpg|png) /block.gif [NC]
重定向非www的版本到www如果你的网站同时可以通过两种形式的URL比如说和来访问到,那么最好将一种地址重定向到另一种地址里,来避免搜索引擎对重复内容做出的处罚。下面是一个能将所有的非www地址重定向到相应的www地址上去的301重定向规则。RewriteEngine onRewriteCond %{HTTPS} (on)?RewriteCond %{HTTP:Host} ^(?!www\.)(.+)$ [NC]RewriteCond %{REQUEST_URI} (.+)RewriteRule .? http(?%1s)://www.%2%3 [R=301,L]
强制SSL或者非SSL到一个指定的位置这里是一个演示如何将SSL强制转到指定的文件夹的示例。只要简单地把下面的规则放到该文件夹下的.htaccess文件里就可以了。RewriteEngine on#Fix missing trailing slash char on foldersRewriteRule ^([^.?]+[^.?/])$ $1/ [R,L]#Redirect non-HTTPS to HTTPSRewriteCond %{HTTP:Host} (.*)RewriteCond %{HTTPS} offRewriteCond %{REQUEST_URI} (.*)RewriteRule .? https://%1%2 [R,L]
而这个示例作用正好相反:将非SSL强制转到指定文件夹。RewriteEngine on#Fix missing trailing slash char on foldersRewriteRule ^([^.?]+[^.?/])$ $1/ [R,L]#Redirect HTTPS to non-HTTPSRewriteCond %{HTTP:Host} (.*)RewriteCond %{HTTPS} onRewriteCond %{REQUEST_URI} (.*)RewriteRule .? %1%2 [R,L]
转移站点位置当你把网站从一个域名移到另一个域名,或者从一个文件夹移动另一个文件夹里的时候,这是经常会遇到的问题。你希望将一个网站的所有请求重定向到另一个网站里,而且不丢失请求资源名以及参数。当你希望保留现有的网页的排名和外链接的时候,它是非常有用的。这个解决方案是在旧的网站服务器上使用ISAPI_Rewrite:RewriteEngine on#Permanent redirect to update old linksRewriteRule (.+) $1 [R=301,L]
平衡负荷仿真这个示例模拟某种DNS轮换负荷平衡技术。假设你有主站和数台web服务器分别注册为www[1-9].。如果你在主服务器上安装了ISAPI_Rewrite,你可以将初始的客户端请求重定向到几台特定服务器,从而在几台服务器之间随机摊开通讯量。一旦已重定向,客户端将一直使用这一台服务器。虽然这种解决方案并不非常理想,但是它确实能分摊你的通讯量并避免在维护会话状态方面发生的问题。使用下面的规则来重定向客户端:RewriteEngine onRewriteMap hosts rnd:hosts.txtRewriteCond %{HTTP:Host} (www)\. [NC]RewriteRule (.*) ${hosts:%1}.$1 [R,L]
下面是hosts.txt文件的内容www www1|www2|www3|www4|www5|www6|www7|www8|www9
你还可以在Apeche文档里找到很多其它有用的例子。它们多数不需要修改就可以在ISAPI_Rewrite3里使用。
相关服务器教程:
相关资源下载:
服务器教程搜索
服务器教程推荐
热门源码推荐
热门服务器教程
©2012&常用正则表达式:
常用正则表达式:&&&&&&&&&&&
中文字符:[\u4e00-\u9fa5]
双字节字符:[^\x00-\xff]
空白行:\s
Email地址:\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}
网址url:^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+
手机(国内):0?(13|14|15|18)[0-9]{9}
电话号码(国内):[0-9-()()]{7,18}
负浮点数:-([1-9]\d*.\d*|0.\d*[1-9]\d*)
正浮点数:[1-9]\d*.\d*|0.\d*[1-9]\d*
匹配整数:-?[1-9]\d*
腾讯QQ号:[1-9]([0-9]{5,11})
邮政编码:\d{6}
ip:(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)
身份证号:\d{17}[\d|x]|\d{15}
格式日期:\d{4}(\-|\/|.)\d{1,2}\1\d{1,2}
正整数:[1-9]\d*
负整数:-[1-9]\d*
用户名:[A-Za-z0-9_\-\u4e00-\u9fa5]+
现在你已经知道几个很有用的元字符了,如\b,.,*,还有\d.正则表达式里还有更多的元字符,比如\s匹配任意的空白符,包括空格,制表符(Tab),换行符,中文全角空格等。\w匹配字母或数字或下划线或汉字等。
对中文/汉字的特殊处理是由.Net提供的正则表达式引擎支持的,其它环境下的具体情况请查看相关文档。
下面来看看更多的例子:
\ba\w*\b匹配以字母a开头的单词&&先是某个单词开始处(\b),然后是字母a,然后是任意数量的字母或数字(\w*),最后是单词结束处(\b)。
好吧,现在我们说说正则表达式里的单词是什么意思吧:就是不少于一个的连续的\w。不错,这与学习英文时要背的成千上万个同名的东西的确关系不大 :)
\d+匹配1个或更多连续的数字。这里的+是和*类似的元字符,不同的是*匹配重复任意次(可能是0次),而+则匹配重复1次或更多次。
\b\w{6}\b&匹配刚好6个字符的单词。
表1.常用的元字符
匹配除换行符以外的任意字符
匹配字母或数字或下划线或汉字
匹配任意的空白符
匹配单词的开始或结束
匹配字符串的开始
匹配字符串的结束
正则表达式引擎通常会提供一个&测试指定的字符串是否匹配一个正则表达式&的方法,如JavaScript里的RegExp.test()方法或.NET里的Regex.IsMatch()方法。这里的匹配是指是字符串里有没有符合表达式规则的部分。如果不使用^和$的话,对于\d{5,12}而言,使用这样的方法就只能保证字符串里包含5到12连续位数字,而不是整个字符串就是5到12位数字。
元字符^(和数字6在同一个键位上的符号)和$都匹配一个位置,这和\b有点类似。^匹配你要用来查找的字符串的开头,$匹配结尾。这两个代码在验证输入的内容时非常有用,比如一个网站如果要求你填写的QQ号必须为5位到12位数字时,可以使用:^\d{5,12}$。
这里的{5,12}和前面介绍过的{2}是类似的,只不过{2}匹配只能不多不少重复2次,{5,12}则是重复的次数不能少于5次,不能多于12次,否则都不匹配。
因为使用了^和$,所以输入的整个字符串都要用来和\d{5,12}来匹配,也就是说整个输入必须是5到12个数字,因此如果输入的QQ号能匹配这个正则表达式的话,那就符合要求了。
和忽略大小写的选项类似,有些正则表达式处理工具还有一个处理多行的选项。如果选中了这个选项,^和$的意义就变成了匹配行的开始处和结束处。
如果你想查找元字符本身的话,比如你查找.,或者*,就出现了问题:你没办法指定它们,因为它们会被解释成别的意思。这时你就得使用\来取消这些字符的特殊意义。因此,你应该使用\.和\*。当然,要查找\本身,你也得用\\.
例如:deerchao\.net匹配deerchao.net,C:\\Windows匹配C:\Windows。
你已经看过了前面的*,+,{2},{5,12}这几个匹配重复的方式了。下面是正则表达式中所有的限定符(指定数量的代码,例如*,{5,12}等):
表2.常用的限定符
代码/语法说明
重复零次或更多次
重复一次或更多次
重复零次或一次
重复n次或更多次
重复n到m次
下面是一些使用重复的例子:
Windows\d+匹配Windows后面跟1个或更多数字
^\w+匹配一行的第一个单词(或整个字符串的第一个单词,具体匹配哪个意思得看选项设置)
要想查找数字,字母或数字,空白是很简单的,因为已经有了对应这些字符集合的元字符,但是如果你想匹配没有预定义元字符的字符集合(比如元音字母a,e,i,o,u),应该怎么办?
很简单,你只需要在方括号里列出它们就行了,像[aeiou]就匹配任何一个英文元音字母,[.?!]匹配标点符号(.或?或!)。
我们也可以轻松地指定一个字符范围,像[0-9]代表的含意与\d就是完全一致的:一位数字;同理[a-z0-9A-Z_]也完全等同于\w(如果只考虑英文的话)。
下面是一个更复杂的表达式:\(?0\d{2}[) -]?\d{8}。
&(&和&)&也是元字符,后面的分组节里会提到,所以在这里需要使用转义。
这个表达式可以匹配几种格式的电话号码,像(010),或022-,或等。我们对它进行一些分析吧:首先是一个转义字符\(,它能出现0次或1次(?),然后是一个0,后面跟着2个数字(\d{2}),然后是)或-或空格中的一个,它出现1次或不出现(?),最后是8个数字(\d{8})。
不幸的是,刚才那个表达式也能匹配010)或(022-这样的&不正确&的格式。要解决这个问题,我们需要用到分枝条件。正则表达式里的分枝条件指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用|把不同的规则分隔开。听不明白?没关系,看例子:
0\d{2}-\d{8}|0\d{3}-\d{7}这个表达式能匹配两种以连字号分隔的电话号码:一种是三位区号,8位本地号(如010-),一种是4位区号,7位本地号()。
\(?0\d{2}\)?[- ]?\d{8}|0\d{2}[- ]?\d{8}这个表达式匹配3位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。你可以试试用分枝条件把这个表达式扩展成也支持4位区号的。
\d{5}-\d{4}|\d{5}这个表达式用于匹配美国的邮政编码。美国邮编的规则是5位数字,或者用连字号间隔的9位数字。之所以要给出这个例子是因为它能说明一个问题:使用分枝条件时,要注意各个条件的顺序。如果你把它改成\d{5}|\d{5}-\d{4}的话,那么就只会匹配5位的邮编(以及9位邮编的前5位)。原因是匹配分枝条件时,将会从左到右地测试每个条件,如果满足了某个分枝的话,就不会去再管其它的条件了。
我们已经提到了怎么重复单个字符(直接在字符后面加上限定符就行了);但如果想要重复多个字符又该怎么办?你可以用小括号来指定子表达式(也叫做分组),然后你就可以指定这个子表达式的重复次数了,你也可以对子表达式进行其它一些操作(后面会有介绍)。
(\d{1,3}\.){3}\d{1,3}是一个简单的IP地址匹配表达式。要理解这个表达式,请按下列顺序分析它:\d{1,3}匹配1到3位的数字,(\d{1,3}\.){3}匹配三位数字加上一个英文句号(这个整体也就是这个分组)重复3次,最后再加上一个一到三位的数字(\d{1,3})。
IP地址中每个数字都不能大于255. 经常有人问我, 01.02.03.04 这样前面带有0的数字, 是不是正确的IP地址呢? 答案是: 是的, IP 地址里的数字可以包含有前导 0 (leading zeroes).
不幸的是,它也将匹配256.300.888.999这种不可能存在的IP地址。如果能使用算术比较的话,或许能简单地解决这个问题,但是正则表达式中并不提供关于数学的任何功能,所以只能使用冗长的分组,选择,字符类来描述一个正确的IP地址:((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)。
理解这个表达式的关键是理解2[0-4]\d|25[0-5]|[01]?\d\d?,这里我就不细说了,你自己应该能分析得出来它的意义。
有时需要查找不属于某个能简单定义的字符类的字符。比如想查找除了数字以外,其它任意字符都行的情况,这时需要用到反义:
表3.常用的反义代码
代码/语法说明
匹配任意不是字母,数字,下划线,汉字的字符
匹配任意不是空白符的字符
匹配任意非数字的字符
匹配不是单词开头或结束的位置
匹配除了x以外的任意字符
匹配除了aeiou这几个字母以外的任意字符
例子:\S+匹配不包含空白符的字符串。
&a[^&]+&匹配用尖括号括起来的以a开头的字符串。
使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。
呃&&其实,组号分配还不像我刚说得那么简单:
分组0对应整个正则表达式
实际上组号分配过程是要从左向右扫描两遍的:第一遍只给未命名组分配,第二遍只给命名组分配--因此所有命名组的组号都大于未命名的组号
你可以使用(?:exp)这样的语法来剥夺一个分组对组号分配的参与权.
后向引用用于重复搜索前面某个分组匹配的文本。例如,\1代表分组1匹配的文本。难以理解?请看示例:
\b(\w+)\b\s+\1\b可以用来匹配重复的单词,像go go, 或者kitty kitty。这个表达式首先是一个单词,也就是单词开始处和结束处之间的多于一个的字母或数字(\b(\w+)\b),这个单词会被捕获到编号为1的分组中,然后是1个或几个空白符(\s+),最后是分组1中捕获的内容(也就是前面匹配的那个单词)(\1)。
你也可以自己指定子表达式的组名。要指定一个子表达式的组名,请使用这样的语法:(?&Word&\w+)(或者把尖括号换成'也行:(?'Word'\w+)),这样就把\w+的组名指定为Word了。要反向引用这个分组捕获的内容,你可以使用\k&Word&,所以上一个例子也可以写成这样:\b(?&Word&\w+)\b\s+\k&Word&\b。
使用小括号的时候,还有很多特定用途的语法。下面列出了最常用的一些:
表4.常用分组语法
分类代码/语法说明
匹配exp,并捕获文本到自动命名的组里
(?&name&exp)
匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)
匹配exp,不捕获匹配的文本,也不给此分组分配组号
匹配exp前面的位置
匹配exp后面的位置
匹配后面跟的不是exp的位置
匹配前面不是exp的位置
(?#comment)
这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读
我们已经讨论了前两种语法。第三个(?:exp)不会改变正则表达式的处理方式,只是这样的组匹配的内容不会像前两种那样被捕获到某个组里面,也不会拥有组号。&我为什么会想要这样做?&&&好问题,你觉得为什么呢?
地球人,是不是觉得这些术语名称太复杂,太难记了?我也有同感。知道有这么一种东西就行了,它叫什么,随它去吧!人若无名,便可专心练剑;物若无名,便可随意取舍&&
接下来的四个用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。最好还是拿例子来说明吧:
断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配。
(?=exp)也叫零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。比如\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.时,它会匹配sing和danc。
(?&=exp)也叫零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式exp。比如(?&=\bre)\w+\b会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading。
假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了),你可以这样查找需要在前面和里面添加逗号的部分:((?&=\d)\d{3})+\b,用它对进行查找时结果是。
下面这个例子同时使用了这两种断言:(?&=\s)\d+(?=\s)匹配以空白符间隔的数字(再次强调,不包括这些空白符)。
负向零宽断言
前面我们提到过怎么查找不是某个字符或不在某个字符类里的字符的方法(反义)。但是如果我们只是想要确保某个字符没有出现,但并不想去匹配它时怎么办?例如,如果我们想查找这样的单词--它里面出现了字母q,但是q后面跟的不是字母u,我们可以尝试这样:
\b\w*q[^u]\w*\b匹配包含后面不是字母u的字母q的单词。但是如果多做测试(或者你思维足够敏锐,直接就观察出来了),你会发现,如果q出现在单词的结尾的话,像Iraq,Benq,这个表达式就会出错。这是因为[^u]总要匹配一个字符,所以如果q是单词的最后一个字符的话,后面的[^u]将会匹配q后面的单词分隔符(可能是空格,或者是句号或其它的什么),后面的\w*\b将会匹配下一个单词,于是\b\w*q[^u]\w*\b就能匹配整个Iraq fighting。负向零宽断言能解决这样的问题,因为它只匹配一个位置,并不消费任何字符。现在,我们可以这样来解决这个问题:\b\w*q(?!u)\w*\b。
零宽度负预测先行断言(?!exp),断言此位置的后面不能匹配表达式exp。例如:\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字;\b((?!abc)\w)+\b匹配不包含连续字符串abc的单词。
同理,我们可以用(?&!exp),零宽度负回顾后发断言来断言此位置的前面不能匹配表达式exp:(?&![a-z])\d{7}匹配前面不是小写字母的七位数字。
请详细分析表达式(?&=&(\w+)&).*(?=&\/\1&),这个表达式最能表现零宽断言的真正用途。
一个更复杂的例子:(?&=&(\w+)&).*(?=&\/\1&)匹配不包含属性的简单HTML标签内里的内容。(?&=&(\w+)&)指定了这样的前缀:被尖括号括起来的单词(比如可能是&b&),然后是.*(任意的字符串),最后是一个后缀(?=&\/\1&)。注意后缀里的\/,它用到了前面提过的字符转义;\1则是一个反向引用,引用的正是捕获的第一组,前面的(\w+)匹配的内容,这样如果前缀实际上是&b&的话,后缀就是&/b&了。整个表达式匹配的是&b&和&/b&之间的内容(再次提醒,不包括前缀和后缀本身)。
小括号的另一种用途是通过语法(?#comment)来包含注释。例如:2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)。
要包含注释的话,最好是启用&忽略模式里的空白符&选项,这样在编写表达式时能任意的添加空格,Tab,换行,而实际使用时这些都将被忽略。启用这个选项后,在#后面到这一行结束的所有文本都将被当成注释忽略掉。例如,我们可以前面的一个表达式写成这样:
# 断言要匹配的文本的前缀
&(\w+)& # 查找尖括号括起来的字母或数字(即HTML/XML标签)
# 前缀结束
# 匹配任意文本
# 断言要匹配的文本的后缀
# 查找尖括号括起来的内容:前面是一个"/",后面是先前捕获的标签
# 后缀结束
贪婪与懒惰
当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。以这个表达式为例:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。
有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。现在看看懒惰版的例子吧:
a.*?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)。
为什么第一个匹配是aab(第一到第三个字符)而不是ab(第二到第三个字符)?简单地说,因为正则表达式有另一条规则,比懒惰/贪婪规则的优先级更高:最先开始的匹配拥有最高的优先权&&The match that begins earliest wins。
表5.懒惰限定符
代码/语法说明
重复任意次,但尽可能少重复
重复1次或更多次,但尽可能少重复
重复0次或1次,但尽可能少重复
重复n到m次,但尽可能少重复
重复n次以上,但尽可能少重复
在C#中,你可以使用来设置正则表达式的处理选项。如:Regex regex = new Regex(@"\ba\w{6}\b", RegexOptions.IgnoreCase);
上面介绍了几个选项如忽略大小写,处理多行等,这些选项能用来改变处理正则表达式的方式。下面是.Net中常用的正则表达式选项:
表6.常用的处理选项
IgnoreCase(忽略大小写)
匹配时不区分大小写。
Multiline(多行模式)
更改^和$的含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,$的精确含意是:匹配\n之前的位置以及字符串结束前的位置.)
Singleline(单行模式)
更改.的含义,使它与每一个字符匹配(包括换行符\n)。
IgnorePatternWhitespace(忽略空白)
忽略表达式中的非转义空白并启用由#标记的注释。
ExplicitCapture(显式捕获)
仅捕获已被显式命名的组。
一个经常被问到的问题是:是不是只能同时使用多行模式和单行模式中的一种?答案是:不是。这两个选项之间没有任何关系,除了它们的名字比较相似(以至于让人感到疑惑)以外。
平衡组/递归匹配
这里介绍的平衡组语法是由.Net Framework支持的;其它语言/库不一定支持这种功能,或者支持此功能但需要使用不同的语法。
有时我们需要匹配像( 100 * ( 50 + 15 ) )这样的可嵌套的层次性结构,这时简单地使用\(.+\)则只会匹配到最左边的左括号和最右边的右括号之间的内容(这里我们讨论的是贪婪模式,懒惰模式也有下面的问题)。假如原来的字符串里的左括号和右括号出现的次数不相等,比如( 5 / ( 3 + 2 ) ) ),那我们的匹配结果里两者的个数也不会相等。有没有办法在这样的字符串里匹配到最长的,配对的括号之间的内容呢?
为了避免(和\(把你的大脑彻底搞糊涂,我们还是用尖括号代替圆括号吧。现在我们的问题变成了如何把xx &aa &bbb& &bbb& aa& yy这样的字符串里,最长的配对的尖括号内的内容捕获出来?
这里需要用到以下的语法构造:
(?'group')&把捕获的内容命名为group,并压入堆栈(Stack)
(?'-group')&从堆栈上弹出最后压入堆栈的名为group的捕获内容,如果堆栈本来为空,则本分组的匹配失败
(?(group)yes|no)&如果堆栈上存在以名为group的捕获内容的话,继续匹配yes部分的表达式,否则继续匹配no部分
(?!)&零宽负向先行断言,由于没有后缀表达式,试图匹配总是失败
如果你不是一个程序员(或者你自称程序员但是不知道堆栈是什么东西),你就这样理解上面的三种语法吧:第一个就是在黑板上写一个"group",第二个就是从黑板上擦掉一个"group",第三个就是看黑板上写的还有没有"group",如果有就继续匹配yes部分,否则就匹配no部分。
我们需要做的是每碰到了左括号,就在压入一个"Open",每碰到一个右括号,就弹出一个,到了最后就看看堆栈是否为空--如果不为空那就证明左括号比右括号多,那匹配就应该失败。正则表达式引擎会进行回溯(放弃最前面或最后面的一些字符),尽量使整个表达式得到匹配。
#最外层的左括号
#最外层的左括号后面的不是括号的内容
(?'Open'&)
#碰到了左括号,在黑板上写一个"Open"
#匹配左括号后面的不是括号的内容
(?'-Open'&)
#碰到了右括号,擦掉一个"Open"
#匹配右括号后面不是括号的内容
(?(Open)(?!))
#在遇到最外层的右括号前面,判断黑板上还有没有没擦掉的"Open";如果还有,则匹配失败
#最外层的右括号
平衡组的一个最常见的应用就是匹配HTML,下面这个例子可以匹配嵌套的&div&标签:&div[^&]*&[^&&]*(((?'Open'&div[^&]*&)[^&&]*)+((?'-Open'&/div&)[^&&]*)+)*(?(Open)(?!))&/div&.
还有些什么东西没提到
上边已经描述了构造正则表达式的大量元素,但是还有很多没有提到的东西。下面是一些未提到的元素的列表,包含语法和简单的说明。你可以在网上找到更详细的参考资料来学习它们--当你需要用到它们的时候。如果你安装了MSDN Library,你也可以在里面找到.net下正则表达式详细的文档。这里的介绍很简略,如果你需要更详细的信息,而又没有在电脑上安装MSDN Library,可以查看。
表7.尚未详细讨论的语法
代码/语法说明
报警字符(打印它的效果是电脑嘀一声)
通常是单词分界位置,但如果在字符类里使用代表退格
制表符,Tab
竖向制表符
ASCII代码中八进制代码为nn的字符
ASCII代码中十六进制代码为nn的字符
Unicode代码中十六进制代码为nnnn的字符
ASCII控制字符。比如\cC代表Ctrl+C
字符串开头(类似^,但不受处理多行选项的影响)
字符串结尾或行尾(不受处理多行选项的影响)
字符串结尾(类似$,但不受处理多行选项的影响)
当前搜索的开头
Unicode中命名为name的字符类,例如\p{IsGreek}
贪婪子表达式
(?&x&-&y&exp)
(?im-nsx:exp)
在子表达式exp中改变处理选项
为表达式后面的部分改变处理选项
(?(exp)yes|no)
把exp当作零宽正向先行断言,如果在这个位置能匹配,使用yes作为此组的表达式;否则使用no
(?(exp)yes)
同上,只是使用空表达式作为no
(?(name)yes|no)
如果命名为name的组捕获到了内容,使用yes作为表达式;否则使用no
(?(name)yes)
同上,只是使用空表达式作为no
阅读(...) 评论()

我要回帖

更多关于 部落冲突助手阵型复制 的文章

 

随机推荐