Rocho.J

人脑是不可靠的, 随时记录感悟并且经常重复!

 

有关正则表达式 -- 转载

三、正则表达式的用途

有时我们在制作网站表单数据处理的时候(尤其是UBB论坛),都需要进行数据验证和字符串替代,特别是UBB论坛要进行大量的数据安全性和字符串替代

邮于一般的论坛不支持HTML语法这就使得用户不能修改字体,不能贴图等等一些功能。这样使得论坛失去了吸引用户的一个强有力的途径。可能说一个强大的论坛在吸引用户数量上还是很重要的。这样就出现了一个UBB解决方案,即在论坛不支持HTML语法的情况下用户仍然可以定制自已贴子的样式,贴图,增加链接,转贴网页等等诸多的功能,可能达到支持HTML语法同样的效果,而且这样可以使得论坛相对于HTML的论坛安全性大大提高。用户基本不能对论坛过行任何恶意攻击。

四、正则表达式的语法规则和标记

  现在我们正式进入则表达式的学习,我会根据实例结合讲解正则表达式的用法,看完后你就会觉得写UBB代码如此简单了,只要你一步一步的跟着我学 看完本文章后你就成为UBB高手了。激动人心的就是你能写出自已的UBB标签来了,再也不用到别人那里去拷贝现成的代码和模板了。 还好VBScritp5.0给我们提供了“正则表达式”对象,只要你的服务器安装了IE5.x,就可以运行了.

  字符描述:

  ^符号匹配字符串的开头。例如:
    ^abc 与“abc xyz”匹配,而不与“xyz abc”匹配

  $符号匹配字符串的结尾。例如:
    abc$ 与“xyz abc”匹配,而不与“abc xyz”匹配
    注意:如果同时使用^符号和$符号,将进行精确匹配。例如:
       ^abc$ 只与“abc”匹配   

  *符号匹配0个或多个前面的字符。例如:
    ab* 可以匹配“ab”、“abb”、“abbb”等

  +符号匹配至少一个前面的字符。例如:
    ab+ 可以匹配“abb”、“abbb”等,但不匹配“ab”。

  ?符号匹配0个或1个前面的字符。例如:
    ab?c? 可以且只能匹配“abc”、“abbc”、“abcc”和“abbcc”

  .符号匹配除换行符以外的任何字符。例如:
    (.)+ 匹配除换行符以外的所有字符串

  x|y匹配“x”或“y”。例如:
    abc|xyz 可匹配 “abc”或 “xyz”,而“ab(c|x)yz”匹配 “abcyz”和“abxyz”

  {n}匹配恰好n次(n为非负整数)前面的字符。例如:
    a{2} 可以匹配“aa“,但不匹配“a”

  {n,}匹配至少n次(n为非负整数)前面的字符。例如:
    a{3,} 匹配“aaa”、“aaaa”等,但不匹配“a”和“aa”。
    注意:a{1,}等价于a+
       a{0,}等价于a*

  {m,n}匹配至少m个,至多n个前面的字符。例如:
    a{1,3} 只匹配“a”、“aa”和“aaa”。
    注意:a{0,1}等价于a?

  [xyz]表示一个字符集,匹配括号中字符的其中之一。例如:
    [abc] 匹配“a”、“b”和“c”

  [^xyz]表示一个否定的字符集。匹配不在此括号中的任何字符。例如:
    [^abc] 可以匹配除“a”、“b”和“c”之外的任何字符

  [a-z]表示某个范围内的字符,匹配指定区间内的任何字符。例如:
    [a-z] 匹配从“a”到“z”之间的任何一个小写字母字符

  [^m-n]表示某个范围之外的字符,匹配不在指定范围内的字符。例如:
    [m-n] 匹配除从“m”到“n”之间的任何字符

  \符号是转义操作符。例如:
    \n 换行符
    \f 分页符
    \r 回车
    \t 制表符
    \v 垂直制表符

    \\ 匹配“\”
    \/ 匹配“/”

    \s 任何白字符,包括空格、制表符、分页符等。等价于“[ \f\n\r\t\v]”
    \S 任何非空白的字符。等价于“^\f\n\r\t\v]”
    \w 任何单词字符,包括字母和下划线。等价于“[A-Za-z0-9_]”
    \W 任何非单词字符。等价于“[^A-Za-z0-9_]”

    \b匹配单词的结尾。例如:
      ve\b 匹配单词“love”等,但不匹配“very”、“even”等

    \B匹配单词的开头。例如:
      ve\B 匹配单词“very”等,但不匹配“love”等

    \d匹配一个数字字符,等价于[0-9]。例如:
      abc\dxyz 匹配“abc2xyz”、“abc4xyz”等,但不匹配“abcaxyz”、“abc-xyz”等

    \D匹配一个非数字字符,等价于[^0-9]。例如:
      abc\Dxyz 匹配“abcaxyz”、“abc-xyz”等,但不匹配“abc2xyz”、“abc4xyz”等

    \NUM匹配NUM个(其中NUM为一个正整数),引用回到记住的匹配。例如:
      (.)\1 匹配两个连续相同的字符。

    \oNUM匹配n(其中n为一个小于256的八进制换码值)。例如:
      \o011 匹配制表符

    \xNUM匹配NUM(其中NUM为一个小于256的十六进制换码值)。例如:
      \x41 匹配字符“A”


五、实例分析

1)在字符串中精确查找链接地址

((http|https|ftp):(\/\/|\\\\)((\w)+[.]){1,}(net|com|cn|org|cc|tv|[0-9]{1,3})(((\/[\~]*|\\[\~]*)
(\w)+)|[.](\w)+)*(((([?](\w)+){1}[=]*))*((\w)+){1}([\&](\w)+[\=](\w)+)*)*)

我们知道,链接地址一般以http或者https或者ftp等形式出现。初步总结一下就是,链接地址必须符合如下条件:

条件1
 以http://或者https://或者ftp://等开头(当然还有其它形式,这里只列出主要的)

条件2
 http://后面必须跟一个单词字符,紧接着单词字符后面的是"."(这样的组合必须出现一次或多次)。紧跟着“.”后面的是域名后缀(如net或者com或者cn等,如果是以IP地址的形式出现就可以是数字)

条件3
 出现完整的链接地址后,还可以出现下一级或者更多级的目录(还要注意个人主页的地址有可能出现"~"符号)

条件4
 链接地址末尾可以带参数。如典型的页数?PageNo=2&action=display等

现在我们用下面的代码来逐个匹配上面的条件——

1、((http|https|ftp):(\/\/|\\\\) 满足条件1
表示http:// http:\\ https:// https:\\ ftp:// ftp:\\都匹配(在这里考虑了某些用户可能把"//"输成“\\”的易发性错误)
注意:"|"表示“或者”,"\"是转义字符。“\/\/”表示"//",“\\\\”表示"\\"

2、((\w)+[.]){1,}(net|com|cn|org|cc|tv|[0-9]{1,3}) 满足条件2
“((\w)+[.]){1,}”表示一个单词字符加一个点号可以出现1次或者多次(这里考虑了某些用户喜欢省略www而将http://www.w3c.com写成http://w3c.com)
“(net|com|cn|org|cc|tv|[0-9]{1,3})”表示必须要以net或者com或者cn或者org或者cc或者tv或者三位以下的数字结束
[0-9]{1,3}表示三位以下的数字,因为ip地址的任何段不能超过255

3、(((\/[\~]*|\\[\~]*)(\w)+)|[.](\w)+)* 满足条件3
“(\/[\~]*|\\[\~]*)”表示可以出现"/~"或者是"\~",(其中“[\~]*”表示 ~ 可以出现也可以不出现),因为不是每个链接地址都有下一级目录
“(\w)+)|[.](\w)+)”表示必须出现一个单词字符(即目录或者是一个带有扩展名的文件)
注意:最后还有一个“*”表示上面括号内的可以出现也可以不出现,否则就只能匹配有下一级目录的链接地址了。

4、(((([?](\w)+){1}[=]*))*((\w)+){1}([\&](\w)+[\=](\w)+)*)*)满足条件4
“((([?](\w)+){1}[=]*))*((\w)+){1}”表示形如"?PageNo=2"的字符串可以出现也可以不出现,如果出现则只能出现一次(因为不可能有两个“?”号出现)。

“([\&](\w)+[\=](\w)+)*)”表示形如“&action=display”的字符串可以出现也可以不出现(因为并不是每个网页都带有两个以上的参数。

整个“((([?](\w)+){1}[=]*))*((\w)+){1}([\&](\w)+[\=](\w)+)*)*”表示形如“?PageNo=2&action=display”的字符串可以出现也可以不出现(即链接地址可以有参数也可以没有参数)


把上面的组合起来,我们就可以匹配一个比较全面的链接地址了。比用简单的“(http:\/\/\S+)”来匹配一个链接地址要好,读者可以自行行测试比较。当然,这段代码还有很多不足之处,希望大家能够继续改进。

2)替代典型的UBB标签:[/b]
我们的目的就是要把[b]成对的替换成<b></b>下面来看我们实现它的模板
  (\[b\])(.+)(\[\/b\])
这里用了"(.+)"来配匹到之间的整个字符串,在替代的时候我们要写成这样
  str=checkexp(re,str,"<b>$2</b>")
(注意:checkexp是我自定义的函数,将在后面给出。这个函数将把[/b]按照我们提供的模板进行替代。)

也许你会问这里出现一个"$2"是什么东东,呵注意了这个$2可是很重要的,它代表了"(.+)"所配匹的整个字符串。
为什么是$2而不是$1、$3呢?因为$1代表(\[b\])所匹配的"[b]"字符串,$3代表(\[\/b\])所匹配的""字符串,显然这里我们需要的是$2而不是$1$3。


六)UBB正则表达模板实例
下面是我写的一个UBB函数,这个函数基本上能使你的论坛成为一个优秀的UBB代码论坛了。当然,通过改进后,你可以得到一个更强大的UBB论坛。

Function ReThestr(face,str)
 dim re,str

 re="\>"
 str=checkexp(re,str,"&gt;")

 re="\<"
 str=checkexp(re,str,"&lt;")

 re="\n\r\n/"
 str=checkexp(re,str,"<P>")

 re=chr(32)
 str=checkexp(re,str,"&nbsp;")

 re="\r"
 str=checkexp(re,str," ")

 re="\[img\]((http:(\/\/|\\\\)){1}((\w)+[.]){1,3}(net|com|cn|org|cc|tv)(((\/[\~]*|\\[\~]*)
(\w)+)|[.](\w)+)*(\w)+[.]{1}(gif|jpg|png))\[\/img\]" ‘’‘’查找图片地址
 str=checkexp(re,str," <img src=‘’‘’$1‘’‘’> ")

 re="\[w\](http:(\/\/|\\\\)((\w)+[.]){1,}(net|com|cn|org|cc|tv)(((\/[\~]*|\\[\~]*)(\w)+)|[.](\w)+)*
(((([?](\w)+){1}[=]*))*((\w)+){1}([\&](\w)+[\=](\w)+)*)*)\[\/w\]" ‘’‘’查找帧地址
 str=checkexp(re,str,"<iframe width=‘’‘’300‘’‘’ height=‘’‘’300‘’‘’ src=‘’‘’$1‘’‘’></iframe>")

 re="([^(‘’‘’>)])(<br>)*((http|https|ftp):(\/\/|\\\\)((\w)+[.]){1,}(net|com|cn|org|cc|tv|([0-9]{1,3}))(((\/[\~]*|\\[\~]*)(\w)+)|[.](\w)+)*(((([?](\w)+){1}[=]*))*((\w)+){1}([\&](\w)+[\=](\w)+)*)*)" ‘’‘’查找链接地址
 str=checkexp(re,str,"$1$2 <a href=‘’‘’$3‘’‘’ target=_blank>$3</a> ")

 re="([^(http://|http:\\)])((www|cn)[.](\w)+[.]{1,}(net|com|cn|org|cc)(((\/[\~]*|\\[\~]*)(\w)+)|[.](\w)+)*
(((([?](\w)+){1}[=]*))*((\w)+){1}([\&](\w)+[\=](\w)+)*)*)" ‘’‘’查找不以http://开头的地址
 str=checkexp(re,str,"$1 <a href=‘’‘’http://$2‘’‘’ target=_blank>$2</a> ")

 re="([^(=)])((\w)+[@]{1}((\w)+[.]){1,3}(\w)+)" ‘’‘’查找邮件地址
 str=checkexp(re,str," <a href=‘’‘’mailto:$2‘’‘’>$2</a> ")

 re="\[0-F]{6})\]((.)+)\[\/color\]" ‘’‘’替换字体色彩
 str=checkexp(re,str,"<font color=‘’‘’$1‘’‘’>$4</font>")

 re="\{1})\]((.)+)\[\/size\]" ‘’‘’替换字体大小
 str=checkexp(re,str,"<font size=‘’‘’$1‘’‘’>$2</font>")

 re="\((.)+)\[\/font\]" ‘’‘’替换字体
 str=checkexp(re,str,"<font face=‘’‘’$1‘’‘’>$3</font>")

 re="(\[b\])(.+)(\[\/b\])" ‘’‘’加粗字体
 str=checkexp(re,str,"<b>$2</b>")

 re="(\[u\])(.+)(\[\/u\])" ‘’‘’下画线
 str=checkexp(re,str,"<u>$2</u>")

 re="(\[li\])(.+)(\[\/li\])" ‘’‘’列表
 str=checkexp(re,str,"<li>$2</li>")

 re="(\[QUOTE\])(.+)(\[\/QUOTE\])" ‘’‘’引用
 str=checkexp(re,str,"<BLOCKQUOTE>引用:<HR SIZE=1>$2<HR SIZE=1></BLOCKQUOTE>")

 re="\){1,3}(\w)+)\](.+)(\[\/email\])" ‘’‘’邮件
 str=checkexp(re,str,"<a href=mailto:$1>$6</a>")

 re="(\[center\])(.+)(\[\/center\])" ‘’‘’居中
 str=checkexp(re,str,"<center>$2</center>")

 re="fuck"
 str=checkexp(re,str,"***")

 re="操"
 str=checkexp(re,str,"***")

 re="sex"
 str=checkexp(re,str,"***")

 re="TMD"
 str=checkexp(re,str,"***")

 re="shit"
 str=checkexp(re,str,"***")

 ReThestr=str
end function

UBB代码如下:


[url] [/url] [email=] [img] [/img]
引用:
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

[li] [/li] [font=impact] [color=Yellow] [size=4]
测试代码如下:

[img] [/img]http://cn.yahoo.com
http://aol.com http://192.168.0.1
www.yahoo.com how are you[/b]
http://page2000.xiloo.com/~page2000?PageNo=2&action=del
lucaihui@cmmail.com 大家好http:\\page2000.shit
<font color=red>http://test.com</font>http://test
全部符合预想结果

 

======================================

 

正则表达式语法

一个正则表达式就是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。

这里有一些可能会遇到的正则表达式示例:

Visual Basic Scripting EditionVBScript匹配
/^\[ \t]*$/ "^\[ \t]*$" 匹配一个空白行。
/\d{2}-\d{5}/ "\d{2}-\d{5}" 验证一个ID 号码是否由一个2位数字,一个连字符以及一个5位数字组成。
/<(.*)>.*<\/\1>/ "<(.*)>.*<\/\1>" 匹配一个 HTML 标记。

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

字符描述
\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 后向引用、或一个八进制转义符。例如,'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} mn 均为非负整数,其中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 集合,在Visual Basic Scripting Edition 中则使用 $0$9 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。
(?: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 匹配 xy。例如,'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 是一个正整数。对所获取的匹配的引用。例如,'(.)\1' 匹配两个连续的相同字符。
\n 标识一个八进制转义值或一个后向引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为后向引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。
\nm 标识一个八进制转义值或一个后向引用。如果 \nm 之前至少有is preceded by at least nm 个获取得子表达式,则 nm 为后向引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的后向引用。如果前面的条件都不满足,若  nm 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm
\nml 如果 n 为八进制数字 (0-3),且 ml 均为八进制数字 (0-7),则匹配八进制转义值 nml。
\un 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。

 

--递归匹配、非贪婪匹配与分组替换2010-05-18 21:26

 

  1. 表达式的递归匹配
  有时分,人们须要用正则表达式来剖析一个盘算式中的括号配对情况。好比, 使用表达式 "\( [^)]* \)" 或者 "\( .*? \)" 可以匹配一对大括号。但是如因括号 内借嵌有一层括号的话 ,如 "( ( ) )",则这种写法将不可以匹配准确,失掉的成果是 "( ( )" 。类似情况的借有 HTML 中收持嵌套的标签如 "<font> </font>" 等。本节将要议论的是,念措施把有嵌套的的成对括号或者成对标签匹配进去。
  匹配未知层次的嵌套:
  有的反则表达式引擎,特地针对这类嵌套降求了收持。并且在栈空间容许的情形上,可以支撑恣意已知层主的嵌套:好比 Perl,PHP,GRETA 等。在 PHP 和 GRETA 中,表达式中使用 "(?R)" 来表现嵌套部门。
  匹配嵌套了已知层主的 "大括号对" 的表达式写法如上:"\( ([^()] | (?R))* \)"。
  [Perl 和 PHP 的示例代码]
  匹配有限层次的嵌套:
  关于不支撑嵌套的正则表达式引擎,只能通功必定的措施来匹配有限层次的嵌套。思绪如下:
  第一步,写一个没有能支撑嵌套的表达式:"\( [^()]* \)","<font>((?!</?font>).)*</font>"。 这两个表达式在匹配有嵌套的白原时,只匹配最外层。
  第两步,写一个可匹配嵌套一层的表达式:"\( ([^()] | \( [^()]* \))* \)"。这个表达式在匹配嵌套层数大于一时,只能匹配最外面的两层,同时,这个表达式也能匹配出有嵌套的文本或许嵌套的最外层。
  匹 配嵌套一层的 "<font>" 标签,表达式为:"<font>((?!</?font>).|(<font>((?!</? font>).)*</font>))*</font>"。这个表达式在匹配 "<font>" 嵌套层数大于一的文本时,只匹配最外面的两层。
  第三步,觅到匹配嵌套(n)层的表达式与 嵌套(n-1)层的表达式之间的关解。比如,可以匹配嵌套(n)层的表达式为:
  [标志头] ( [匹配 [本忘头]和 [本忘头] 之外的表达式] | [匹配 n-1 层的表达式] )* [标志头]
  归头来望后面编写的“可匹配嵌套一层”的表达式:
  \( ( [^()] | \(([^()])*\) )* \)
  <font> ( (?!</?font>). | (<font>((?!</?font>).)*</font>) )* </font>
  PHP 和 GRETA 的烦琐之处在于,匹配嵌套(n-1)层的表达式用 (?R) 表现:
  \( ( [^()] | (?R) )* \)
  第四步,依此类推,否以编写出匹配有限(n)层的表达式。这类方法写进去的表达式,固然望下去很少,但是这种表达式经由编译先,匹配效力仍旧是很下的。
  2. 非贪婪匹配的效率
  能够有不长的己和人一样,有过这样的阅历:当我们要匹配相似 "<td>外容</td>" 或许 "减细" 这样的文本时,人们依据正背预搜寻功效写出这样的表达式:"<td>([^<]|<(?!/td>))*< /td>" 或者 "<td>((?!</td>).)*</td>"。
  该发明非贪婪匹配之时,恍然 小悟,同样功效的表达式能够写失如斯简略:"<td>.*?</td>"。 顿时光大喜过望,但凡按边界匹配的处所,绝质使用繁捷的是贪心匹配 ".*?"。特殊是关于庞杂的里达式来道,采取非贪婪匹配 ".*?" 写进去的表达式的确非简洁了许少。
  但是,当一个表达式中,有多个非贪婪匹配时,或者多个未知匹配次数的表达式时,这个表达式将可能具有效率下的陷阱。有时分,匹配快度缓失莫名巧妙,以至开端疑惑正则表达式能否适用。
  效力陷阱的发生:
  在本坐基本文章外,对非贪婪匹配的描写中说到:“如因少匹配就会招致整个表达式匹配失败的时分,与贪婪模式类似,非贪婪模式会最大限制的再匹配一些,以使整个表达式匹配成过。”
  详细的匹配进程是这样的:
  "非贪婪部门" 先匹配起码次数,然后尝试匹配 "左正的表达式"。
  如果右侧的表达式匹配败过,则整个表达式匹配停止。如因右侧表达式匹配得成,则 "非贪婪局部" 将增长匹配一次,然后再尝试匹配 "右侧的表达式"。
  假如右侧的表达式又匹配得成,则 "非贪婪局部" 将再增添匹配一次。再尝试匹配 "右侧的表达式"。
  依此类推,最初失掉的成果是 "非贪婪部门" 以绝能够长的匹配次数,使整个表达式匹配胜利。或许最末仍旧匹配失利。
  该 一个表达式中无少个非贪心匹配,以表达式 "d(\w+?)d(\w+?)z" 为例,对于于第一个括号中的 "\w+?" 来说,左边的 "d(\w+?)z" 属于它的 "右侧的表达式",关于第两个括号中的 "\w+?" 来道,左边的 "z" 属于它的 "左正的表达式"。
  当 "z" 匹配得败时,第二个 "\w+?" 会 "增长匹配一次",再尝试匹配 "z"。假如第二个 "\w+?" 不管怎样 "添加匹配次数",曲至整篇文本停止,"z" 皆不能匹配,这么表现 "d(\w+?)z" 匹配失败,也便是说第一个 "\w+?" 的 "右侧" 匹配失成。此时,第一个 "\w+?" 会删加匹配一次,然后再进行 "d(\w+?)z" 的匹配。轮回后面所道的进程,曲至第一个 "\w+?" 有论怎样 "删减匹配次数",后边的 "d(\w+?)z" 皆不能匹配时,整个表达式才宣布匹配失败。
  其真,为了使整个里达式匹配胜利,贪婪匹 配也会恰当的“争出”曾经婚配的字符。因而贪婪匹配也无相似的情形。该一个表达式外有较少的已知匹配次数的表达式时,为了争零个表达式匹配败过,各个贪心 或者是贪婪的表达式皆要入止尝试加长或增添匹配主数,由彼轻易构成一个小轮回的尝试,形成了很少的匹配时光。原白之所以称之为“陷阱”,由于那类效力答题去 去没有难发觉。
  举例:"d(\w+?)d(\w+?)d(\w+?)z" 匹配 "ddddddddddd..." 时,将破费较少一段时光能力断定出匹配失利。
  效率陷阱的防止:
  躲任效率陷阱的准绳是:防止“多沉轮回”的“尝试匹配”。并不是说非贪婪匹配就是不佳的,只是在应用非贪婪匹配的时候,需求注意躲任过多“循环尝试”的答题。
  情 况一:对于只要一个非贪婪或者贪婪匹配的表达式来说,不具有效率陷阱。也就是说,要匹配类似 "<td> 内容 </td>" 这样的文本,表达式 "<td>([^<]|<(?!/td>))*</td>" 和 "<td>((?!</td>).)*</td>" 和 "<td>.*?</td>" 的效率是完整雷同的。
  情形两:假如一个表达式中有多个未知匹配次数的表达式,当避免进行不用要的尝试匹配。
  好比,对表达式 "<script language='(.*?)'>(.*?)</script>" 来道, 假如后面局部表达式在碰到 "<script language='vbscript'>" 时匹配胜利后,然后边的 "(.*?)</script>" 却匹配失利,将招致第一个 ".*?" 增添匹配次数再尝试。而对于表达式实正目标,争第一个 ".*?" 增长匹配败“vbscript'>”是不合错误的,果此这种尝试是不用要的尝试。
  果此,对依附边界来辨认的表达式,不要让未知匹配次数的部分跨 过它的边界。后里的表达式中,第一个 ".*?" 当该改写成 "[^']*"。后边那个 ".*?" 的左边再出有未知匹配次数的表达式,果此这个非贪婪匹配出无效率陷阱。于是,这个匹配足本块的表达式,应当写成:"<script language='([^']*)'>(.*?)</script>" 更佳。
  3.正则表达式-合组结构
  分组构造使您可以捕获子表达式组并进步具有非捕获预测先行和回顾后收润饰符的正则表达式的效率。下表描写了正则表达式分组构造。
  合组结构 阐明
  ( ) 逮获匹配的女字符串(或者非捕获组;有闭具体疑作,请参睹反则表达式选项中的 ExplicitCapture 选项)。使用 () 的捕捉依据右括号的次序自 1 开端主动编号。捕获元荤编号为整的第一个捕捉非由零个正则表达式模式匹配的白原。
  (?<name> ) 将婚配的女字符串捕捉到一个组实称或者编号称号外。用于 name 的字符串没有能包括免何本面符号,并且不能以数字扫尾。能够使用双引号为代秃括号,例如 (?'name')。
  (?<name1-name2> ) 均衡组订义。增除先前定义的 name2 组的定义并在 name1 组中亡储后后定义的 name2 组战以后组之间的距离。假如不决义 name2 组,则匹配将归溯。因为增除 name2 的最初一个定义会隐示 name2 的先后定义,因而当结构容许将 name2 组的逮获堆栈用做计数器以和踪嵌套构制(如括号)。在彼构制中,name1 是可选的。否以使用单引号为代秃括号,例如 (?'name1-name2')。
  (?: ) 非捕获组。
  (?imnsx-imnsx: ) 利用或禁用子表达式中指订的选项。例如,(?i-s: ) 将翻开不区分小大写并禁用单行模式。有闭具体疑作,请参睹正则表达式选项。
  (?= ) 整阔度正预测先行续直言。仅当子表达式在此地位的右侧匹配时才继承匹配。例如,\w+(?=\d) 与后和数字的单词匹配,而不取该数字匹配。此构制不会来溯。
  (?! ) 零宽度背预测先行断行。仅当子表达式不在此位放的右侧匹配时才继续匹配。例如,400电话,\b(?!un)\w+\b 与不以 un 扫尾的单词匹配。
  (?<= ) 零阔度正来顾后收续直言。仅当子表达式在此位放的左侧匹配时才继续匹配。例如,(?<=19)99 与跟在 19 前面的 99 的真例匹配。此构造不会回溯。
  (?<! ) 整阔度背归顾先收续直言。仅当子表达式不在此地位的右正匹配时才继承匹配。
  (?> ) 非回溯子表达式(也称为“贪婪”子表达式)。该子表达式仅完整匹配一次,然后就不会逐段介入来溯了。(也就是说,该子表达式仅与可由该子表达式独自匹配的字符串匹配。)
  命 名捕获依据左括号的自右到左的次序按次第编号(取是命实捕捉相似),但正在对一切非命名捕捉入行计数之先才开端对于命名捕捉进止编号。例如,模式 ((?<One>abc)/d+)?(?<Two>xyz)(.*) 按编号战称号发生上列逮获组。(编号为 0 的第一个捕获老是指零个模式)。
  编号 名称 模式
  0 0(默许名称) ((?<One>abc)/d+)?(?<Two>xyz)(.*)
  1 1(默许称号) ((?<One>abc)/d+)
  2 2(默许实称) (.*)
  3 1 (?<One>abc)
  4 2 (?<Two>xyz)
  4.正则表达式-替代和合组
  替换使用 | 字符来容许在两个或多个替代选项之间进行挑选。例如,可以扩大章节题目正则表达式,以前往比章题目范畴更狭的匹配项。但是,这并不象您可能以为的这样繁 单。为换匹配 | 字符两边的绝可能最大的表达式。您可能觉得,上面的表达式匹配呈现外行尾和行头、前面和一个或两个数字的 Chapter 或 Section:
  /^Chapter|Section [1-9][0-9]{0,1}$ /
  很遗憾,上面的正则表达式要么匹配行尾的单词 Chapter,要么匹配行尾的单词 Section 及跟在其后的免何数字。如果赢进字符串是 Chapter 22,那么下里的表达式只匹配单词 Chapter。如果输出字符串是 Section 22,那么该表达式匹配 Section 22。
  若要使正则表达式更难于节制,否以使用括号 来限造替代的范畴,便,确保它只利用于两个双词 Chapter 战 Section。但非,括号也用于创立子表达式,并能够捕捉它们以求当前使用,那一面在有闭正背援用的这一节道述。通功正在下面的正则表达式的恰当地位加减 括号,便可以使当反则表达式匹配 Chapter 1 或 Section 3。
  上面的正则表达式使用括号来组开 Chapter 和 Section,以即表达式准确天止做用:
  /^(Chapter|Section) [1-9][0-9]{0,1}$ /
  虽 然那些里达式准确施展做用,但 Chapter| Section 两边的括号借会使失两个匹配双词中的免何一个被捕捉以求未来使用。因为正在下面的表达式外只要一组括号,因而,只无一个被捕捉的“女匹配项”。能够通功使用 RegExp 对于象的 $ 1-$ 9 属性来援用彼子婚配项。
  在下面的示例中,您只须要使用括号来组开单词 Chapter 和 Section 之间的挑选。若要避免匹配被保管以备未来使用,请在括号内正则表达式模式之前搁放 ?:。下里的改动降供雷同的才能而不保留子匹配项:
  /^(?:Chapter|Section) [1-9][0-9]{0,1}$ /
  除 ?: 元字符外,两个其他非捕获元字符创立被称为“预测先行”匹配的某些外容。正向猜测先行使用 ?= 指定,它匹配处于括号中匹配正则表达式模式的止初面的搜寻字符串。正向预测先行使用 ?! 指订,它匹配处于取正则表达式模式不匹配的字符串的止初正点的搜索字符串。
  例 如,假定您有一个文档,该文档包括指背 Windows 3.1、Windows 95、Windows 98 和 Windows NT 的援用。再入一步真设,您须要更旧当文档,将指向 Windows 95、Windows 98 和 Windows NT 的一切引用更改为 Windows 2000。上面的正则表达式(这是一个正向猜测后止的示例)匹配 Windows 95、Windows 98 和 Windows NT:
  /Windows(?=95 |98 |NT )/
  觅到一处匹配后,松交灭便在匹配的文本(不包含猜测后行中的字符)之后搜寻下一处匹配。例如,假如下面的表达式匹配 Windows 98,将在 Windows 之后而不是在 98 之后继承搜索
  本文来自CSDN专主,:http://blog.csdn.net/fandelei1982/archive/2009/09/ 28/4606118.aspx

 

============================

\w*?ab         ->  匹配到以ab结尾的内容(含ab). 如:ffabcadbcsxab^ab, 匹配结果ffab,sxab,ab

\w+?ab        ->  匹配到已ab结尾的内容 如:ffabcadbcsxab^ab, 匹配结果ffab,sxab
  

=========================================

忽略大小写来着~ 

这里给段搜的资料,巨细的如果你想摸得透彻还是自己写几段代码试试吧

对应的内嵌标志表达式是 (?i),它有四种形式:
1,(?i)
2,(?-i)
3,(?i:X)
4,(?-i:X)
不带有 - 的是开标志,带有 - 的是关标志。

把上面的代码改成这样: 

Java code 
public class Test {
    public static void main(String[] args) {
        String str = "Book";
        String regex = "(?i)book"; 
        System.out.println(str.matches(regex));
    }
} 


我们就达到了同样的效果,当然这样并不是最好的,因为字符串中只有 B 是大写的,
我们没有必要把所有的字符都进行不区分大小写匹配,我们可以在打开标志,用 (?i) 的
第二种形式马上关掉它:
    String regex = "(?i)b(?-i)ook";

这样的话,只有 b 是区分大小写了,而 (?-i) 后面的还是得区分大小写匹配的。这样写
可能看上去很不顺眼,我们还能使用第 3 种形式直接指定某些字符是不区分大小写的。
    String regex = "(?i:b)ook";

这样的表达式与上面的那个在语义上是相同的。就效率上肯定是优于一下子开,一下子关的。

可见内嵌标志表达式要比指定编译参数的功能强大许多。

使用建议:如果能确定某些字符的大小写时,尽量使用已确定的字符,对于不确定的可以采用
(?i:X) 的方式指定。因此打开不区分大小写开关时,对匹配的性能是有一定影响的。
 
 

=========================================================
源:
<table>
    <tr>
     Tar_ServiceA
    </tr>
    <tr>
     Tar_TESTtest
    </tr>
    <tr>
     Tar_ServiceC
    </tr>
</table>

 

正则: <tr>[\n]?.*?Tar_TESTtest[\n]?.*?</tr>

结果:  第二个tr

posted on 2011-10-10 12:26  RJ  阅读(1542)  评论(0)    收藏  举报

导航