人间五十年,万事如梦幻。一度生存者,岂有长不灭? 注册 | 登陆
浏览模式: 标准 | 列表2007年10月的文章

正则表达式收藏(五)之微软的正则

正则表达式

如果原来没有使用过正则表达式,那么可能对这个术语和概念会不太熟悉。不过,它们并不是您想象的那么新奇。

请回想一下在硬盘上是如何查找文件的。您肯定会使用 ? 和 * 字符来帮助查找您正寻找的文件。? 字符匹配文件名中的单个字符,而 * 则匹配一个或多个字符。一个如 'data?.dat' 的模式可以找到下述文件:

data1.dat

data2.dat

datax.dat

dataN.dat

如果使用 * 字符代替 ? 字符,则将扩大找到的文件数量。'data*.dat' 可以匹配下述所有文件名:

data.dat

data1.dat

data2.dat

data12.dat

datax.dat

dataXYZ.dat

尽管这种搜索文件的方法肯定很有用,但也十分有限。? 和 * 通配符的有限能力可以使你对正则表达式能做什么有一个概念,不过正则表达式的功能更强大,也更灵活。

正则表达式简介(微软)--3.使用正则表达式

使用正则表达式

在典型的搜索和替换操作中,必须提供要查找的确切文字。这种技术对于静态文本中的简单搜索和替换任务可能足够了,但是由于它缺乏灵活性,因此在搜索动态文本时就有困难了,甚至是不可能的。

使用正则表达式,就可以:

1.测试字符串的某个模式。例如,可以对一个输入字符串进行测试,看在该字符串是否存在一个电话号码模式或一个信用卡号码模式。这称为数据有效性验证。

2.替换文本。可以在文档中使用一个正则表达式来标识特定文字,然后可以全部将其删除,或者替换为别的文字。

3.根据模式匹配从字符串中提取一个子字符串。可以用来在文本或输入字段中查找特定文字。

例如,如果需要搜索整个 web 站点来删除某些过时的材料并替换某些HTML 格式化标记,则可以使用正则表达式对每个文件进行测试,看在该文件中是否存在所要查找的材料或 HTML 格式化标记。用这个方法,就可以将受影响的文件范围缩小到包含要删除或更改的材料的那些文件。然后可以使用正则表达式来删除过时的材料,最后,可以再次使用正则表达式来查找并替换那些需要替换的标记。

另一个说明正则表达式非常有用的示例是一种其字符串处理能力还不为人所知的语言。VBScript 是 Visual Basic 的一个子集,具有丰富的字符串处理功能。与 C 类似的 Visual Basic Scripting Edition 则没有这一能力。正则表达式给 Visual Basic Scripting Edition 的字符串处理能力带来了明显改善。不过,可能还是在 VBScript 中使用正则表达式的效率更高,它允许在单个表达式中执行多个字符串操作。

正则表达式简介(微软)--4.正则表达式语法

正则表达式语法

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

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

Visual Basic VBScript 匹配
Scripting Edition

/^\[ \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} 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 集合,在
Visual Basic Scripting Edition 中则使用 $0…$9 属性。要
匹配圆括号字符,请使用 '\(' 或 '\)'。

(?:pattern) 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹
配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合
一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就
是一个比 'industry|industries' 更简略的表达式。

(?=pattern) 正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符
串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后
使用。例如,'Windows (?=95|98|NT|2000)' 能匹配"Windows
2000"中的"Windows",但不能匹配"Windows3 .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是一个正整数。对所获取的匹配的引用。
例如,'(.)\1' 匹配两个连续的相同字符。

\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 匹配版权符号 (?)。

正则表达式简介(微软)--5.建立正则表达式

建立正则表达式

构造正则表达式的方法和创建数学表达式的方法一样。也就是用多种元字符与操作符将小的表达式结合在一起来创建更大的表达式。

可以通过在一对分隔符之间放入表达式模式的各种组件来构造一个正则表达式。对 Visual Basic Scripting Edition 而言,分隔符为一对正斜杠 (/) 字符。例如:

/expression/

对 VBScript 而言,则采用一对引号 ("") 来确定正则表达式的边界。例如:

"expression"

在上面所示的两个示例中,正则表达式模式 (expression) 均存储在RegExp 对象的Pattern 属性中。

正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。

Tags: 正则表达式

正则表达式收藏(四)之MySQL的正则

正则表达式(regex)是定义复杂查询的一个强有力的工具。 这里是一个简单的资料,它忽略了一些详细的信息。
  正则表达式定义了一个字符串的规则。最简单的正则表达式不包含任何保留字。例如,正则表达式hello只和字符串“hello”匹配。

  一般的正则表达式使用了某些特殊的结构,所以它能匹配更多的字符串。例如,正则表达式hello|word既能匹配字符串“hello”也能匹配字符串“word”。

  举一个更复杂一点的例子,正则表达式B[an]*s可以匹配字符串“Bananas”、“Baaaaas”、“Bs”以及其他任何以B开头以s结尾的字符串,中间可以包括任意个a和任意个n的组合。

  一个正则表达式中的可以使用以下保留字

^

所匹配的字符串以后面的字符串开头

mysql> select "fonfo" REGEXP "^fo$"; -> 0(表示不匹配)

mysql> select "fofo" REGEXP "^fo"; -> 1(表示匹配)

$

所匹配的字符串以前面的字符串结尾

mysql> select "fono" REGEXP "^fono$"; -> 1(表示匹配)

mysql> select "fono" REGEXP "^fo$"; -> 0(表示不匹配)

.

匹配任何字符(包括新行)

mysql> select "fofo" REGEXP "^f.*"; -> 1(表示匹配)

mysql> select "fonfo" REGEXP "^f.*"; -> 1(表示匹配)

a*

匹配任意多个a(包括空串)

mysql> select "Ban" REGEXP "^Ba*n"; -> 1(表示匹配)

mysql> select "Baaan" REGEXP "^Ba*n"; -> 1(表示匹配)

mysql> select "Bn" REGEXP "^Ba*n"; -> 1(表示匹配)

a+

匹配任意多个a(不包括空串)

mysql> select "Ban" REGEXP "^Ba+n"; -> 1(表示匹配)

mysql> select "Bn" REGEXP "^Ba+n"; -> 0(表示不匹配)

a?

匹配一个或零个a

mysql> select "Bn" REGEXP "^Ba?n"; -> 1(表示匹配)

mysql> select "Ban" REGEXP "^Ba?n"; -> 1(表示匹配)

mysql> select "Baan" REGEXP "^Ba?n"; -> 0(表示不匹配)

de|abc

匹配de或abc

mysql> select "pi" REGEXP "pi|apa"; -> 1(表示匹配)

mysql> select "axe" REGEXP "pi|apa"; -> 0(表示不匹配)

mysql> select "apa" REGEXP "pi|apa"; -> 1(表示匹配)

mysql> select "apa" REGEXP "^(pi|apa)$"; -> 1(表示匹配)

mysql> select "pi" REGEXP "^(pi|apa)$"; -> 1(表示匹配)

mysql> select "pix" REGEXP "^(pi|apa)$"; -> 0(表示不匹配)

(abc)*

匹配任意多个abc(包括空串)

mysql> select "pi" REGEXP "^(pi)*$"; -> 1(表示匹配)

mysql> select "pip" REGEXP "^(pi)*$"; -> 0(表示不匹配)

mysql> select "pipi" REGEXP "^(pi)*$"; -> 1(表示匹配)

{1}

{2,3}

这是一个更全面的方法,它可以实现前面好几种保留字的功能

a*

可以写成a{0,}

a+

可以写成a{1,}

a?

可以写成a{0,1}

  在{}内只有一个整型参数i,表示字符只能出现i次;在{}内有一个整型参数i,后面跟一个“,”,表示字符可以出现i次或i次以上;在{}内只有一个整型参数i,后面跟一个“,”,再跟一个整型参数j,表示字符只能出现i次以上,j次以下(包括i次和j次)。其中的整型参数必须大于等于0,小于等于 RE_DUP_MAX(默认是255)。 如果有两个参数,第二个必须大于等于第一个

[a-dX]

匹配“a”、“b”、“c”、“d”或“X”

[^a-dX]

匹配除“a”、“b”、“c”、“d”、“X”以外的任何字符。

“[”、“]”必须成对使用

mysql> select "aXbc" REGEXP "[a-dXYZ]"; -> 1(表示匹配)

mysql> select "aXbc" REGEXP "^[a-dXYZ]$"; -> 0(表示不匹配)

mysql> select "aXbc" REGEXP "^[a-dXYZ]+$"; -> 1(表示匹配)

mysql> select "aXbc" REGEXP "^[^a-dXYZ]+$"; -> 0(表示不匹配)

mysql> select "gheis" REGEXP "^[^a-dXYZ]+$"; -> 1(表示匹配)

mysql> select "gheisa" REGEXP "^[^a-dXYZ]+$"; -> 0(表示不匹配)

[[.characters.]] 表示比较元素的顺序。在括号内的字符顺序是唯一的。但是括号中可以包含通配符,所以他能匹配更多的字符。举例来说:正则表达式[[.ch.]]*c匹配chchcc的前五个字符。

[=character_class=]

表示相等的类,可以代替类中其他相等的元素,包括它自己。例如,如果o和(+)是一个相等的类的成员,那么[[=o=]]、[[=(+)=]]和[o(+)]是完全等价的。

[:character_class:]

在括号里面,在[:和:]中间是字符类的名字,可以代表属于这个类的所有字符。字符类的名字有: alnum、digit、punct、alpha、graph、space、blank、lower、upper、cntrl、print和xdigit

mysql> select "justalnums" REGEXP "[[:alnum:]]+"; -> 1(表示匹配)

mysql> select "!!" REGEXP "[[:alnum:]]+"; -> 0(表示不匹配)

[[:<:]]

[[:>:]]

分别匹配一个单词开头和结尾的空的字符串,这个单词开头和结尾都不是包含在alnum中的字符也不能是下划线。

mysql> select "a word a" REGEXP "[[:<:]]word[[:>:]]"; -> 1(表示匹配)

mysql> select "a xword a" REGEXP "[[:<:]]word[[:>:]]"; -> 0(表示不匹配)

mysql> select "weeknights" REGEXP "^(wee|week)(knights|nights)$"; -> 1(表示匹配)

Tags: 正则表达式

正则表达式收藏(三)之高级技巧

什么是RE?
  想必各位大大在做文件查找的时侯都有使用过万用字符”*”,比如说想查找在Windows目录下所有的Word文件时,你可能就会用”*.doc”这样的方式来做查找,因为”*”所代表的是任意的字符。RE所做的就是类似这样的功能,但其功能更为强大。

  写程序时,常需要比对字符串是否符合特定样式,RE最主要的功能就是来描述这特定的样式,因此可以将RE视为特定样式的描述式,举个例子来说,”\w+”所代表的就是任何字母与数字所组成的非空字符串(non-null string)。在.NET framework中提供了非常强大的类别库,藉此可以很轻易的使用RE来做文字的查找与取代、对复杂标头的译码及验证文字等工作。
接下来,就让我们来体验一些例子吧。

  一些简单的例子
  假设要查找文章中Elvis后接有alive的文字符串的话,使用RE可能会经过下列的过程,括号是所下RE的意思:

  1. elvis (查找elvis)

  上述代表所要查找的字符顺序为elvis。在.NET中可以设定乎略字符的大小写,所以”Elvis”、”ELVIS”或者是”eLvIs”都是符合1所下的RE。但因为这只管字符出现的顺序为elvis,所以pelvis也是符合1所下的RE。可以用2的RE来改进。

  2. \belvis\b (将elvis视为一整体的字查找,如elvis、Elvis乎略字符大小写时)
“\b”在RE中有特别的意思,在上述的例子中所指的就是字的边界,所以\belvis\b用\b把elvis的前后边界界定出来,也就是要elvis这个字。

  假设要将同一行里elvis后接有alive的文字符串找出来,此时就会用到另外二个特别意义的字符”.”及”*”。”.”所代表就是除了换行字符的任意字符,而”*”所代表的是重复*之前项目直到找到符合RE的字符串。所以”.*”所指的就是除了换行字符外的任意数目的字符数。所以查找同一行里elvis后接有alive的文字符串找出来,则可下如3之RE。

  3. \belvis\b.*\balive\b (查找elvis后面接有alive的文字符串,如elvis is alive)

  用简单之特别字符就可以组成功能强大的RE,但也发现当使用越来越多的特别字符时,RE就会越来越难看得懂了。


再看看另外的例子
  组成有效的电话号码

  假使要从网页上收集顾客格式为xxx-xxxx的7位数字的电话号码,其中x是数字,RE可能会这样写。

  4. \b\d\d\d-\d\d\d\d (查找七位数字之电话号码,如123-1234)
  每一个\d代表一个数字。”-”则是一般的连字符号,为避免太多重复的\d,RE可以改写成如5的方式。

  5. \b\d{3}-\d{4} (查找七位数字电话号码较好的方法,如123-1234)
  在\d后的{3},代表重复前一个项目三次,也就是相等于\d\d\d。

  RE的学习及测试工具 Expresso

  因为RE不易阅读及使用者容易会下错RE的特性,Jim大大开发了一个工具软件Expresso,用来帮助使用者学习及测试RE,除了上面所述的网址之外,也可以上Ultrapico网站。安装完expresso后,在expression%20%20library中,jim大大把文章的例子都建立在其中,可以边看文章边测试,也可以试着修改范例所下的re,马上可以看到结果,小弟觉得非常好用。各位大大可以试试。/"。安装完Expresso后,在Expression Library中,Jim大大把文章的例子都建立在其中,可以边看文章边测试,也可以试着修改范例所下的RE,马上可以看到结果,小弟觉得非常好用。各位大大可以试试。

  .NET中RE的基础概念
  特殊字符

  有些字符有特别的意义,比如之前所看到的”\b”、”.”、”*”、”\d”等。”\s”所代表的是任意空格符,比如说spaces、tabs、newlines等.。”\w”代表是任意字母或数字字符。

  再看一些例子吧
  6. \ba\w*\b (查找a开头的字,如able)
  这RE描述要查找一个字的开始边界(\b),再来是字母”a”,再加任意数目的字母数字(\w*),再接结束这个字的结束边界(\b)。

  7. \d+ (查找数字字符串)
  “+”和”*”非常相似,除了+至少要重复前面的项目一次。也就是说至少有一个数字。

  8. \b\w{6}\b (查找六个字母数字的字,如ab123c)

  下表为RE常用的特殊字符

  . 除了换行字符的任意字符
  \w 任意字母数字字符
  \s 任意空格符
  \d 任意数字字符
  \b 界定字的边界
  ^ 文章的开头,如”^The'' 用以表示出现于文章开头的字符串为”The”
  $ 文章的结尾,如”End$”用以表示出现在文章的结尾为”End”
  特殊字符”^”及”$”是用来查找某些字必需是文章的开头或结尾,这在验证输入是否符合某一样式时特别用有,比如说要验证七位数字的电话号码,可能会输入如下9的RE。

  9. ^\d{3}-\d{4}$ (验证七位数字之电话号码)

  这和第5个RE相同,但其前后都无其它的字符,也就是整串字符串只有这七个数字的电话号码。在.NET中如果设定Multiline这个选项,则”^”和”$”会每行进行比较,只要某行的开头结尾符合RE即可,而不是整个文章字符串做一次比较。

  转意字符(Escaped characters)

  有时可能会需要”^”、”$”单纯的字面意义(literal meaning)而不要将它们当成特殊字符,此时”\”字符就是用来移除特殊字符特别意义的字符,因此”\^”、”\.”、”\\”所代表的就是”^”、”.”、”\”的字面意义。

  重复前述项目

  在前面看过”{3}”及”*”可以用来重复前述字符,之后我们会看到如何用同样的语法重复整个次描述(subexpressions)。下表是使用重复前述项目的一些方式。

  * 重复任意次数
  + 重复至少一次
  ? 重复零次或一次
  {n} 重复n次
  {n,m} 重复至少n次,但不超过m次
  {n,} 重复至少n次

  再来试一些例子吧

  10. \b\w{5,6}\b (查找五个或六个字母数字字符的字,如as25d、d58sdf等)
  11. \b\d{3}\s\d{3}-\d{4} (查找十个数字的电话号码,如800 123-1234)
  12. \d{3}-\d{2}-\d{4} (查找社会保险号码,如 123-45-6789)
  13. ^\w* (每行或整篇文章的第一个字)
  在Espresso可试试有Multiline和没Multiline的不同。

  匹配某范围的字符

  有时需要查找某些特定的字符时怎么辨?这时中括号”[]”就派上了用场。因此[aeiou]所要查找的是”a”、”e”、”i”、”o”、”u”这些元音,[.?!]所要查找的是”.”、”?”、”!”这些符号,在中括号中的特殊字符的特别意义都会被移除,也就是解译成单纯的字面意义。也可以指定某些范围的字符,如”[a-z0-9]”,所指的就是任意小写字母或任意数字。

  接下来再看一个比较初复杂查找电话号码的RE例子

  14. \(?\d{3}[( ] \s?\d{3}[- ]\d{4} (查找十位数字之电话号码,如(080) 333-1234 )

  这样的RE可查找出较多种格式的电话号码,如(080) 123-4567、511 254 6654等。”\(?”代表一个或零个左小括号”(“,而”[( ]”代表查找一个右小括号”)”或空格符,”\s?”指一个或零个空格符组。但这样的RE会将类似”800) 45-3321”这样的电话找出来,也就是括号没有对称平衡的问题,之后会学到择一(alternatives)来决解这样的问题。

  不包含在某特定字符组里(Negation)

  有时需要查找在包含在某特定字符组里的字符,下表说明如何做类似这样的描述。

  \W 不是字母数字的任意字符
  \S 不是空格符的任意字符
  \D 不是数字字符的任意字符
  \B 不在字边界的位置
  [^x] 不是x的任意字符
  [^aeiou] 不是a、e、i、o、u的任意字符

  15. \S+ (不包含空格符的字符串)

  择一(Alternatives)

  有时会需要查找几个特定的选择,此时”|”这个特殊字符就派上用场了,举例来说,要查找五个数字及九个数字(有”-”号)的邮政编码。

  16. \b\d{5}-\d{4}\b|\b\d{5}\b (查找五个数字及九个数字(有”-”号)的邮政编码)

  在使用Alternatives时需要注意的是前后的次序,因为RE在Alternatives中会优先选择符合最左边的项目,16中,如果把查找五个数字的项目放在前面,则这RE只会找到五个数字的邮政编码。了解了择一,可将14做更好的修正。

  17. (\(\d{3}\)|\d{3})\s?\d{3}[- ]\d{4} (十个数字的电话号码)

  群组(Grouping)

  括号可以用来介定一个次描述,经由次描述的介定,可以针对次描述做重复或及他的处理。

  18. (\d{1,3}\.){3}\d{1,3} (寻找网络地址的简单RE)

  此RE的意思第一个部分(\d{1,3}\.){3},所指的是,数字最小一位最多三位,并且后面接有”.”符号,此类型的共有三个,之后再接一到三位的数字,也就是如192.72.28.1这样的数字。

  但这样会有个缺点,因为网络地址数字最多只到255,但上述的RE只要是一到三位的数字都是符合的,所以这需要让比较的数字小于256才行,但只单独使用RE并无法做这样的比较。在19中使用择一来将地址的限制在所需要的范围内,也就是0到255。

  19. ((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?) (寻找网络地址)

  有没有发觉RE越来越像外星人说的话了?就以简单的寻找网络地址,直接看RE都满难理解的哩。

  Expresso Analyzer View

  Expresso提供了一个功能,它可以将所下的RE变成树状的说明,一组组的分开说明,提供了一个好的除错环境。其它的功能,如部分符合(Partial Match只查找反白RE的部分)及除外符合(Exclude Match只不查找反白RE的部分)就留给各位大大试试啰。

  当次描述用括号群组起来时,符合次描述的文字可用在之后的程序处理或RE本身。在预设的情型下,所符合的群组是由数字命名,由1开始,由顺序是由左至右,这自动群组命名,可在Expresso中的skeleton view或result view中看到。

  Backreference是用来查找群组中抓取的符合文字所相同的文字。举例来说”\1”所指符合群组1所抓取的文字。

  20. \b(\w+)\b\s*\1\b (寻找重复字,此处说的重复是指同样的字,中间有空白隔开如dog dog这样的字)
(\w+)会抓取至少一个字符的字母或数字的字,并将它命名为群组1,之后是查找任意空格符,再接和群组1相同的文字。

  如果不喜欢群组自动命名的1,也可以自行命名,以上述例子为例,(\w+)改写为(?<Word>\w+),这就是将所抓取的群组命名为Word,Backreference就要改写成为\k<Word>
21. \b(?<Word>\w+)\b\s*\k<Word>\b (使用自行命名群组抓取重复字)

  使用括号还有许多特别的语法元素,比较通用的列表如下:

  抓取(Captures)
  (exp) 符合exp并抓取它进自动命名的群组
  (?<name>exp) 符合exp并抓取它进命名的群组name
  (?:exp) 符合exp,不抓取它
  Lookarounds
  (?=exp) 符合字尾为exp的文字
  (?<=exp) 符合前缀为exp的文字
  (?!exp) 符合后面没接exp字尾的文字
  (?<!exp) 符合前面没接exp前缀的文字
  批注Comment
  (?#comment) 批注

  Positive Lookaround

  接下来要谈的是lookahead及lookbehind assertions。它们所查找的是目前符合之前或之后的文字,并不包含目前符合本身。这些就如同”^”及”\b”特殊字符,本身并不会对应任何文字(用来界定位置),也因此称做是zero-width assertions,看些例子也许会清楚些。

  (?=exp)是一个”zero-width positive lookahead assertion”。它指的就是符合字尾为exp的文字,但不包含exp本身。

  22. \b\w+(?=ing\b) (字尾为ing的字,比如说filling所符合的就是fill)
(?<=exp)是一个”zero-width positive lookbehind assertion”。它指的就是符合前缀为exp的文字,但不包含exp本身。

  23. (?<=\bre)\w+\b (前缀为re的字,比如说repeated所符合的就是peated)
  24. (?<=\d)\d{3}\b (在字尾的三位数字,且之前接一位数字)
  25. (?<=\s)\w+(?=\s) (由空格符分隔开的字母数字字符串)

  Negative Lookaround

  之前有提到,如何查找一个非特定或非在特定群组的字符。但如果只是要验证某字符不存在而不要对应这些字符进来呢?举个例子来说,假设要查找一个字,它的字母里有q但接下来的字母不是u,可以用下列的RE来做。

  26. \b\w*q[^u]\w*\b (一个字,其字母里有q但接下来的字母不是u)

  这样的RE会有一个问题,因为[^u]要对应一个字符,所以若q是字的最后一个字母,[^u]这样的下法就会将空格符对应下去,结果就有可能会符合二个字,比如说”Iraq haha”这样的文字。使用Negative Lookaround就能解决这样的问题。

  27. \b\w*q(?!u)\w*\b (一个字,其字母里有q但接下来的字母不是u)
  这是”zero-width negative lookahead assertion”。

  28. \d{3}(?!\d) (三个位的数字,其后不接一个位数字)

  同样的,可以使用(?<!exp),”zero-width negative lookbehind assertion”,来符合前面没接exp前缀的文字符串。

  29. (?<![a-z ])\w{7} (七个字母数字的字符串,其前面没接字母或空格)

30. (?<=<(\w+)>.*(?=<\/\1> (HTML卷标间的文字)
  这使用lookahead及lookbehind assertion来取出HTML间的文字,不包括HTML卷标。

  请批注(Comments Please)
  括号还有个特殊的用途就是用来包住批注,语法为”(?#comment)”,若设定”Ignore Pattern Whitespace”选项,则RE中的空格符当RE使用时会乎略。此选项设定时,”#”之后的文字会乎略。

  31. HTML卷标间的文字,加上批注

  (?<=  #查找前缀,但不包含它
  <(\w+)> #HTML标签
  ) #结束查找前缀
  .* #符合任何文字
  (?= #查找字尾,但不包含它
  <\/\1> #符合所抓取群组1之字符串,也就是前面小括号的HTML标签
  ) #结束查找字尾

  寻找最多字符的字及最少字符的字(Greedy and Lazy)
  当RE下要查找一个范围的重复时(如”.*”),它通常会寻找最多字符的符合字,也就是Greedy matching。举例来说。

  32. a.*b (开始为a结束为b的最多字符的符合字)

  若有一字符串是”aabab”,使用上述RE所得到的符合字符串就是”aabab”,因为这是寻找最多字符的字。有时希望是符合最少字符的字也就是lazy matching。只要将重复前述项目的表加上问号(?)就可以把它们全部变成lazy matching。因此”*?”代表的就是重复任意次数,但是使用最少重复的次数来符合。举个例子来说:

  33. a.*?b (开始为a结束为b的最少字符的符合字)

  若有一字符串是”aabab”,使用上述RE第一个所得到的符合字符串就是”aab”再来是”ab”,因为这是寻找最少字符的字。

  *? 重复任意次数,最少重复次数为原则
  +? 重复至少一次,最少重复次数为原则
  ?? 重复零次或一次,最少重复次数为原则
  {n,m}? 重复至少n次,但不超过m次,最少重复次数为原则
  {n,}? 重复至少n次,最少重复次数为原则

还有什么没提到呢?

  到目前为止,已经提到了许多建立RE的元素,当然还有许多元素没有提到,下表整理了一些没提到的元素,在最左边的字段的数字是说明在Expresso中的例子。

  # 语法 说明

  \a Bell 字符
  \b 通常是指字的边界,在字符组里所代表的就是backspace
  \t Tab

  34 \r Carriage return

  \v Vertical Tab
  \f From feed

  35 \n New line
  \e Escape

  36 \nnn ASCII八位码为nnn的字符

  37 \xnn 十六位码为nn的字符

  38 \unnnn Unicode为nnnn的字符

  39 \cN Control N字符,举例来说Ctrl-M是\cM

  40 \A 字符串的开始(和^相似,但不需籍由multiline选项)

  41 \Z 字符串的结尾
  \z 字符串的结尾

  42 \G 目前查找的开始

  43 \p{name} Unicode 字符组名称为name的字符,比如说\p{Lowercase_Letter} 所指的就是小写字
  (?>exp) Greedy次描述,又称之为non-backtracking次描述。这只符合一次且不采backtracking。

  44 (?<x>-<y>exp)

  or (?-<y>exp) 平衡群组。虽复杂但好用。它让已命名的抓取群组可以在堆栈中操作使用。(小弟对这个也是不太懂哩)

  45 (?im-nsx:exp) 为次描述exp更改RE选项,比如(?-i:Elvis)就是把Elvis大乎略大小写的选项关掉

  46 (?im-nsx) 为之后的群组更改RE选项。
  (?(exp)yes|no) 次描述exp视为zero-width positive lookahead。若此时有符合,则yes次描述为下一个符合标的,若否,则no 次描述为下一个符合标的。
  (?(exp)yes) 和上述相同但无no次描述
  (?(name)yes|no) 若name群组为有效群组名称,则yes次描述为下一个符合标的,若否,则no 次描述为下一个符合标的。

  47 (?(name)yes) 和上述相同但无no次描述


From:Internet  
想必很多人都对正则表达式都头疼.今天,我以我的认识,加上网上一些文章,希望用常人都可以理解的表达方式.来和大家分享学习经验.

开篇,还是得说说 ^ 和 $ 他们是分别用来匹配字符串的开始和结束,以下分别举例说明


"^The": 开头一定要有"The"字符串;
"of despair$": 结尾一定要有"of despair" 的字符串;


那么,
"^abc$": 就是要求以abc开头和以abc结尾的字符串,实际上是只有abc匹配
"notice": 匹配包含notice的字符串


你可以看见如果你没有用我们提到的两个字符(最后一个例子),就是说 模式(正则表达式) 可以出现在被检验字符串的任何地方,你没有把他锁定到两边

接着,说说 '*', '+',和 '?',
他们用来表示一个字符可以出现的次数或者顺序. 他们分别表示:
"zero or more"相当于{0,},
"one or more"相当于{1,},
"zero or one."相当于{0,1}, 这里是一些例子:


"ab*": 和ab{0,}同义,匹配以a开头,后面可以接0个或者N个b组成的字符串("a", "ab", "abbb", 等);
"ab+": 和ab{1,}同义,同上条一样,但最少要有一个b存在 ("ab", "abbb", 等.);
"ab?":和ab{0,1}同义,可以没有或者只有一个b;
"a?b+$": 匹配以一个或者0个a再加上一个以上的b结尾的字符串.

要点, '*', '+',和 '?'只管它前面那个字符.


你也可以在大括号里面限制字符出现的个数,比如


"ab{2}": 要求a后面一定要跟两个b(一个也不能少)("abb");
"ab{2,}": 要求a后面一定要有两个或者两个以上b(如"abb", "abbbb", 等.);
"ab{3,5}": 要求a后面可以有2-5个b("abbb", "abbbb", or "abbbbb").



现在我们把一定几个字符放到小括号里,比如:

"a(bc)*": 匹配 a 后面跟0个或者一个"bc";
"a(bc){1,5}": 一个到5个 "bc."


还有一个字符 '│', 相当于OR 操作:


"hi│hello": 匹配含有"hi" 或者 "hello" 的 字符串;
"(b│cd)ef": 匹配含有 "bef" 或者 "cdef"的字符串;
"(a│b)*c": 匹配含有这样多个(包括0个)a或b,后面跟一个c
的字符串;


一个点('.')可以代表所有的单一字符,不包括"\n"

如果,要匹配包括"\n"在内的所有单个字符,怎么办?

对了,用'[\n.]'这种模式.


"a.[0-9]": 一个a加一个字符再加一个0到9的数字
"^.{3}$": 三个任意字符结尾 .




中括号括住的内容只匹配一个单一的字符


"[ab]": 匹配单个的 a 或者 b ( 和 "a│b" 一样);
"[a-d]": 匹配'a' 到'd'的单个字符 (和"a│b│c│d" 还有 "[abcd]"效果一样); 一般我们都用[a-zA-Z]来指定字符为一个大小写英文
"^[a-zA-Z]": 匹配以大小写字母开头的字符串
"[0-9]%": 匹配含有 形如 x% 的字符串
",[a-zA-Z0-9]$": 匹配以逗号再加一个数字或字母结尾的字符串


你也可以把你不想要得字符列在中括号里,你只需要在总括号里面使用'^' 作为开头 "%[^a-zA-Z]%" 匹配含有两个百分号里面有一个非字母的字符串.

要点:^用在中括号开头的时候,就表示排除括号里的字符

为了PHP能够解释,你必须在这些字符面前后加'',并且将一些字符转义.

不要忘记在中括号里面的字符是这条规路的例外—在中括号里面, 所有的特殊字符,包括(''), 都将失去他们的特殊性质 "[*\+?{}.]"匹配含有这些字符的字符串.

还有,正如regx的手册告诉我们: "如果列表里含有 ']', 最好把它作为列表里的第一个字符(可能跟在'^'后面). 如果含有'-', 最好把它放在最前面或者最后面, or 或者一个范围的第二个结束点[a-d-0-9]中间的‘-’将有效.

看了上面的例子,你对{n,m}应该理解了吧.要注意的是,n和m都不能为负整数,而且n总是小于m. 这样,才能 最少匹配n次且最多匹配m次. 如"p{1,5}"将匹配 "pvpppppp"中的前五个p

下面说说以\开头的

\b 书上说他是用来匹配一个单词边界,就是...比如've\b',可以匹配love里的ve而不匹配very里有ve

\B 正好和上面的\b相反.例子我就不举了

.....突然想起来....可以到
http://www.phpv.net/article.php/251 看看其它用\ 开头的语法



好,我们来做个应用:

如何构建一个模式来匹配 货币数量 的输入

构建一个匹配模式去检查输入的信息是否为一个表示money的数字。我们认为一个表示money的数量有四种方式: "10000.00" 和 "10,000.00",或者没有小数部分, "10000" and "10,000". 现在让我们开始构建这个匹配模式:

^[1-9][0-9]*$

这是所变量必须以非0的数字开头.但这也意味着 单一的 "0" 也不能通过测试. 以下是解决的方法:

^(0│[1-9][0-9]*)$

"只有0和不以0开头的数字与之匹配",我们也可以允许一个负号在数字之前:

^(0│-?[1-9][0-9]*)$

这就是: "0 或者 一个以0开头 且可能 有一个负号在前面的数字." 好了,现在让我们别那么严谨,允许以0开头.现在让我们放弃 负号 , 因为我们在表示钱币的时候并不需要用到. 我们现在指定 模式 用来匹配小数部分:

^[0-9]+(\.[0-9]+)?$

这暗示匹配的字符串必须最少以一个阿拉伯数字开头. 但是注意,在上面模式中 "10." 是不匹配的, 只有 "10" 和 "10.2" 才可以. (你知道为什么吗)

^[0-9]+(\.[0-9]{2})?$

我们上面指定小数点后面必须有两位小数.如果你认为这样太苛刻,你可以改成:

^[0-9]+(\.[0-9]{1,2})?$

这将允许小数点后面有一到两个字符. 现在我们加上用来增加可读性的逗号(每隔三位), 我们可以这样表示:

^[0-9]{1,3}(,[0-9]{3})*(\.[0-9]{1,2})?$

不要忘记 '+' 可以被 '*' 替代 如果你想允许空白字符串被输入话 (为什么?). 也不要忘记反斜杆 ’\’ 在php字符串中可能会出现错误 (很普遍的错误).

现在,我们已经可以确认字符串了, 我们现在把所有逗号都去掉 str_replace(",", "", $money) 然后在把类型看成 double然后我们就可以通过他做数学计算了.


再来一个:

构造检查email的正则表达式

在一个完整的email地址中有三个部分:
1. 用户名 (在 '@' 左边的一切),
2.'@',
3. 服务器名(就是剩下那部分).

用户名可以含有大小写字母阿拉伯数字,句号 ('.'), 减号('-'), and 下划线 ('_'). 服务器名字也是符合这个规则,当然下划线除外.

现在, 用户名的开始和结束都不能是句点. 服务器也是这样. 还有你不能有两个连续的句点他们之间至少存在一个字符,好现在我们来看一下怎么为用户名写一个匹配模式:

^[_a-zA-Z0-9-]+$

现在还不能允许句号的存在. 我们把它加上:

^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*$

上面的意思就是说: "以至少一个规范字符(除了.)开头,后面跟着0个或者多个以点开始的字符串."

简单化一点, 我们可以用 eregi()取代 ereg().eregi()对大小写不敏感, 我们就不需要指定两个范围 "a-z" 和 "A-Z" – 只需要指定一个就可以了:

^[_a-z0-9-]+(\.[_a-z0-9-]+)*$

后面的服务器名字也是一样,但要去掉下划线:

^[a-z0-9-]+(\.[a-z0-9-]+)*$

好. 现在只需要用”@”把两部分连接:

^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*$


这就是完整的email认证匹配模式了,只需要调用

eregi(‘^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*$ ’,$eamil)

就可以得到是否为email了
正则表达式的其他用法

提取字符串

ereg() and eregi() 有一个特性是允许用户通过正则表达式去提取字符串的一部分(具体用法你可以阅读手册). 比如说,我们想从 path/URL 提取文件名 – 下面的代码就是你需要:

ereg("([^\\/]*)$", $pathOrUrl, $regs);
echo $regs[1];

高级的代换

ereg_replace() 和 eregi_replace()也是非常有用的: 假如我们想把所有的间隔负号都替换成逗号:


ereg_replace("[ \n\r\t]+", ",", trim($str));

最后,我把另一串检查EMAIL的正则表达式让看文章的你来分析一下.

"^[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+'.'@'.'[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.'.'[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$"

如果能方便的读懂,那这篇文章的目的就达到了.

Tags: 正则表达式

正则表达式收藏(二)之入门

1.      什么是正则表达式

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

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

 

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

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

 

3.      文字符号

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

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

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

要注意,正则表达式引擎缺省是大小写敏感的。除非你告诉引擎忽略大小写,否则<<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:\temp”,你要用正则表达式<<C:\\temp>>。而在C++中,正则表达式则变成了“C:\\\\temp”。

 

·        不可显示字符

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

<<\t>>代表Tab(0x09)

<<\r>>代表回车符(0x0D)

<<\n>>代表换行符(0x0A)

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

 

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

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

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

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

 

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

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

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

 

 

5.      字符集

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

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

 

·        字符集的一些应用

查找一个可能有拼写错误的单词,比如<<sep[ae]r[ae]te>> 或 <<li[cs]en[cs]e>>。

查找程序语言的标识符,<<A-Za-z_][A-Za-z_0-9]*>>。(*表示重复0或多次)

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

 

·        取反字符集

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

需要记住的很重要的一点是,取反字符集必须要匹配一个字符。<<q[^u]>>并不意味着:匹配一个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”。

 

·        字符集的简写

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

<<\d>>代表<<[0-9]>>;

<<\w>>代表单词字符。这个是随正则表达式实现的不同而有些差异。绝大多数的正则表达式实现的单词字符集都包含了<<A-Za-z0-9_]>>。

<<\s>>代表“白字符”。这个也是和不同的实现有关的。在绝大多数的实现中,都包含了空格符和Tab符,以及回车换行符<<\r\n>>。

字符集的缩写形式可以用在方括号之内或之外。<<\s\d>>匹配一个白字符后面紧跟一个数字。<<[\s\d]>>匹配单个白字符或数字。<<[\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,}和+ 的作用一样。

你可以用<<\b[1-9][0-9]{3}\b>>匹配1000~9999之间的数字(“\b”表示单词边界)。<<\b[1-9][0-9]{2,4}\b>>匹配一个在100~99999之间的数字。

 

·        注意贪婪性

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

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

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

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

 

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

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

 

·        用懒惰性取代贪婪性

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

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

 

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

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

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

 

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

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

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

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

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

其他语言和正则表达式库也采用了Perl的术语定义。当在.NET Framework中使用正则表达式类时,你可以用类似下面的语句来激活单行模式:Regex.Match(“string”,”regex”,RegexOptions.SingleLine)

 

 

·        保守的使用点号“.”

点号可以说是最强大的元字符。它允许你偷懒:用一个点号,就能匹配几乎所有的字符。但是问题在于,它也常常会匹配不该匹配的字符。

我会以一个简单的例子来说明。让我们看看如何匹配一个具有“mm/dd/yy”格式的日期,但是我们想允许用户来选择分隔符。很快能想到的一个方案是<<\d\d.\d\d.\d\d>>。看上去它能匹配日期“02/12/03”。问题在于02512703也会被认为是一个有效的日期。

<<\d\d[-/.]\d\d[-/.]\d\d>>看上去是一个好一点的解决方案。记住点号在一个字符集里不是元字符。这个方案远不够完善,它会匹配“99/99/99”。而<<[0-1]\d[-/.][0-3]\d[-/.]\d\d>>又更进一步。尽管他也会匹配“19/39/99”。你想要你的正则表达式达到如何完美的程度取决于你想达到什么样的目的。如果你想校验用户输入,则需要尽可能的完美。如果你只是想分析一个已知的源,并且我们知道没有错误的数据,用一个比较好的正则表达式来匹配你想要搜寻的字符就已经足够。

 

8.      字符串开始和结束的锚定

锚定和一般的正则表达式符号不同,它不匹配任何字符。相反,他们匹配的是字符之前或之后的位置。“^”匹配一行字符串第一个字符前的位置。<<^a>>将会匹配字符串“abc”中的a。<<^b>>将不会匹配“abc”中的任何字符。

类似的,$匹配字符串中最后一个字符的后面的位置。所以<<c$>>匹配“abc”中的c。

 

·        锚定的应用

在编程语言中校验用户输入时,使用锚定是非常重要的。如果你想校验用户的输入为整数,用<<^\d+$>>。

用户输入中,常常会有多余的前导空格或结束空格。你可以用<<^\s*>>和<<\s*$>>来匹配前导空格或结束空格。

 

·        使用“^”和“$”作为行的开始和结束锚定

如果你有一个包含了多行的字符串。例如:“first line\n\rsecond line”(其中\n\r表示一个新行符)。常常需要对每行分别处理而不是整个字符串。因此,几乎所有的正则表达式引擎都提供一个选项,可以扩展这两种锚定的含义。“^”可以匹配字串的开始位置(在f之前),以及每一个新行符的后面位置(在\n\r和s之间)。类似的,$会匹配字串的结束位置(最后一个e之后),以及每个新行符的前面(在e与\n\r之间)。

在.NET中,当你使用如下代码时,将会定义锚定匹配每一个新行符的前面和后面位置:Regex.Match("string", "regex", RegexOptions.Multiline)

应用:string str = Regex.Replace(Original, "^", "> ", RegexOptions.Multiline)--将会在每行的行首插入“> ”。

 

·        绝对锚定

<<\A>>只匹配整个字符串的开始位置,<<\Z>>只匹配整个字符串的结束位置。即使你使用了“多行模式”,<<\A>>和<<\Z>>也从不匹配新行符。

即使\Z和$只匹配字符串的结束位置,仍然有一个例外的情况。如果字符串以新行符结束,则\Z和$将会匹配新行符前面的位置,而不是整个字符串的最后面。这个“改进”是由Perl引进的,然后被许多的正则表达式实现所遵循,包括Java,.NET等。如果应用<<^[a-z]+$>>到“joe\n”,则匹配结果是“joe”而不是“joe\n”。
9.      单词边界

 

元字符<<\b>>也是一种对位置进行匹配的“锚”。这种匹配是0长度匹配。

有4种位置被认为是“单词边界”:

1)        在字符串的第一个字符前的位置(如果字符串的第一个字符是一个“单词字符”)

2)        在字符串的最后一个字符后的位置(如果字符串的最后一个字符是一个“单词字符”)

3)        在一个“单词字符”和“非单词字符”之间,其中“非单词字符”紧跟在“单词字符”之后

4)        在一个“非单词字符”和“单词字符”之间,其中“单词字符”紧跟在“非单词字符”后面

 “单词字符”是可以用“\w”匹配的字符,“非单词字符”是可以用“\W”匹配的字符。在大多数的正则表达式实现中,“单词字符”通常包括<<[a-zA-Z0-9_]>>。

例如:<<\b4\b>>能够匹配单个的4而不是一个更大数的一部分。这个正则表达式不会匹配“44”中的4。

换种说法,几乎可以说<<\b>>匹配一个“字母数字序列”的开始和结束的位置。

 

“单词边界”的取反集为<<\B>>,他要匹配的位置是两个“单词字符”之间或者两个“非单词字符”之间的位置。

 

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

让我们看看把正则表达式<<\bis\b>>应用到字符串“This island is beautiful”。引擎先处理符号<<\b>>。因为\b是0长度 ,所以第一个字符T前面的位置会被考察。因为T是一个“单词字符”,而它前面的字符是一个空字符(void),所以\b匹配了单词边界。接着<<i>>和第一个字符“T”匹配失败。匹配过程继续进行,直到第五个空格符,和第四个字符“s”之间又匹配了<<\b>>。然而空格符和<<i>>不匹配。继续向后,到了第六个字符“i”,和第五个空格字符之间匹配了<<\b>>,然后<<is>>和第六、第七个字符都匹配了。然而第八个字符和第二个“单词边界”不匹配,所以匹配又失败了。到了第13个字符i,因为和前面一个空格符形成“单词边界”,同时<<is>>和“is”匹配。引擎接着尝试匹配第二个<<\b>>。因为第15个空格符和“s”形成单词边界,所以匹配成功。引擎“急着”返回成功匹配的结果。

 

10.  选择符

正则表达式中“|”表示选择。你可以用选择符匹配多个可能的正则表达式中的一个。

如果你想搜索文字“cat”或“dog”,你可以用<<cat|dog>>。如果你想有更多的选择,你只要扩展列表<<cat|dog|mouse|fish>>。

选择符在正则表达式中具有最低的优先级,也就是说,它告诉引擎要么匹配选择符左边的所有表达式,要么匹配右边的所有表达式。你也可以用圆括号来限制选择符的作用范围。如<<\b(cat|dog)\b>>,这样告诉正则引擎把(cat|dog)当成一个正则表达式单位来处理。

·        注意正则引擎的“急于表功”性

正则引擎是急切的,当它找到一个有效的匹配时,它会停止搜索。因此在一定条件下,选择符两边的表达式的顺序对结果会有影响。假设你想用正则表达式搜索一个编程语言的函数列表:Get,GetValue,Set或SetValue。一个明显的解决方案是<<Get|GetValue|Set|SetValue>>。让我们看看当搜索SetValue时的结果。

因为<<Get>>和<<GetValue>>都失败了,而<<Set>>匹配成功。因为正则导向的引擎都是“急切”的,所以它会返回第一个成功的匹配,就是“Set”,而不去继续搜索是否有其他更好的匹配。

和我们期望的相反,正则表达式并没有匹配整个字符串。有几种可能的解决办法。一是考虑到正则引擎的“急切”性,改变选项的顺序,例如我们使用<<GetValue|Get|SetValue|Set>>,这样我们就可以优先搜索最长的匹配。我们也可以把四个选项结合起来成两个选项:<<Get(Value)?|Set(Value)?>>。因为问号重复符是贪婪的,所以SetValue总会在Set之前被匹配。

一个更好的方案是使用单词边界:<<\b(Get|GetValue|Set|SetValue)\b>>或<<\b(Get(Value)?|Set(Value)?\b>>。更进一步,既然所有的选择都有相同的结尾,我们可以把正则表达式优化为<<\b(Get|Set)(Value)?\b>>。

 

 

11.  组与向后引用

把正则表达式的一部分放在圆括号内,你可以将它们形成组。然后你可以对整个组使用一些正则操作,例如重复操作符。

要注意的是,只有圆括号“()”才能用于形成组。“[]”用于定义字符集。“{}”用于定义重复操作。

当用“()”定义了一个正则表达式组后,正则引擎则会把被匹配的组按照顺序编号,存入缓存。当对被匹配的组进行向后引用的时候,可以用“\数字”的方式进行引用。<<\1>>引用第一个匹配的后向引用组,<<\2>>引用第二个组,以此类推,<<\n>>引用第n个组。而<<\0>>则引用整个被匹配的正则表达式本身。我们看一个例子。

假设你想匹配一个HTML标签的开始标签和结束标签,以及标签中间的文本。比如<B>This is a test</B>,我们要匹配<B>和</B>以及中间的文字。我们可以用如下正则表达式:“<([A-Z][A-Z0-9]*)[^>]*>.*?</\1>”

首先,“<”将会匹配“<B>”的第一个字符“<”。然后[A-Z]匹配B,[A-Z0-9]*将会匹配0到多次字母数字,后面紧接着0到多个非“>”的字符。最后正则表达式的“>”将会匹配“<B>”的“>”。接下来正则引擎将对结束标签之前的字符进行惰性匹配,直到遇到一个“</”符号。然后正则表达式中的“\1”表示对前面匹配的组“([A-Z][A-Z0-9]*)”进行引用,在本例中,被引用的是标签名“B”。所以需要被匹配的结尾标签为“</B>”

你可以对相同的后向引用组进行多次引用,<<([a-c])x\1x\1>>将匹配“axaxa”、“bxbxb”以及“cxcxc”。如果用数字形式引用的组没有有效的匹配,则引用到的内容简单的为空。

一个后向引用不能用于它自身。<<([abc]\1)>>是错误的。因此你不能将<<\0>>用于一个正则表达式匹配本身,它只能用于替换操作中。

后向引用不能用于字符集内部。<<(a)[\1b]>>中的<<\1>>并不表示后向引用。在字符集内部,<<\1>>可以被解释为八进制形式的转码。

向后引用会降低引擎的速度,因为它需要存储匹配的组。如果你不需要向后引用,你可以告诉引擎对某个组不存储。例如:<<Get(?:Value)>>。其中“(”后面紧跟的“?:”会告诉引擎对于组(Value),不存储匹配的值以供后向引用。

·        重复操作与后向引用

当对组使用重复操作符时,缓存里后向引用内容会被不断刷新,只保留最后匹配的内容。例如:<<([abc]+)=\1>>将匹配“cab=cab”,但是<<([abc])+=\1>>却不会。因为([abc])第一次匹配“c”时,“\1”代表“c”;然后([abc])会继续匹配“a”和“b”。最后“\1”代表“b”,所以它会匹配“cab=b”。

应用:检查重复单词--当编辑文字时,很容易就会输入重复单词,例如“the the”。使用<<\b(\w+)\s+\1\b>>可以检测到这些重复单词。要删除第二个单词,只要简单的利用替换功能替换掉“\1”就可以了。

 

 

·        组的命名和引用

在PHP,Python中,可以用<<(?P<name>group)>>来对组进行命名。在本例中,词法?P<name>就是对组(group)进行了命名。其中name是你对组的起的名字。你可以用(?P=name)进行引用。

.NET的命名组

.NET framework也支持命名组。不幸的是,微软的程序员们决定发明他们自己的语法,而不是沿用Perl、Python的规则。目前为止,还没有任何其他的正则表达式实现支持微软发明的语法。

下面是.NET中的例子:

(?<first>group)(?’second’group)

正如你所看到的,.NET提供两种词法来创建命名组:一是用尖括号“<>”,或者用单引号“’’”。尖括号在字符串中使用更方便,单引号在ASP代码中更有用,因为ASP代码中“<>”被用作HTML标签。

要引用一个命名组,使用\k<name>或\k’name’.

当进行搜索替换时,你可以用“${name}”来引用一个命名组。

 

12.  正则表达式的匹配模式

本教程所讨论的正则表达式引擎都支持三种匹配模式:

<</i>>使正则表达式对大小写不敏感,

<</s>>开启“单行模式”,即点号“.”匹配新行符

<</m>>开启“多行模式”,即“^”和“$”匹配新行符的前面和后面的位置。

 

·        在正则表达式内部打开或关闭模式

如果你在正则表达式内部插入修饰符(?ism),则该修饰符只对其右边的正则表达式起作用。(?-i)是关闭大小写不敏感。你可以很快的进行测试。<<(?i)te(?-i)st>>应该匹配TEst,但是不能匹配teST或TEST.

 

13.  原子组与防止回溯

在一些特殊情况下,因为回溯会使得引擎的效率极其低下。

让我们看一个例子:要匹配这样的字串,字串中的每个字段间用逗号做分隔符,第12个字段由P开头。

我们容易想到这样的正则表达式<<^(.*?,){11}P>>。这个正则表达式在正常情况下工作的很好。但是在极端情况下,如果第12个字段不是由P开头,则会发生灾难性的回溯。如要搜索的字串为“1,2,3,4,5,6,7,8,9,10,11,12,13”。首先,正则表达式一直成功匹配直到第12个字符。这时,前面的正则表达式消耗的字串为“1,2,3,4,5,6,7,8,9,10,11,”,到了下一个字符,<<P>>并不匹配“12”。所以引擎进行回溯,这时正则表达式消耗的字串为“1,2,3,4,5,6,7,8,9,10,11”。继续下一次匹配过程,下一个正则符号为点号<<.>>,可以匹配下一个逗号“,”。然而<<,>>并不匹配字符“12”中的“1”。匹配失败,继续回溯。大家可以想象,这样的回溯组合是个非常大的数量。因此可能会造成引擎崩溃。

用于阻止这样巨大的回溯有几种方案:

一种简单的方案是尽可能的使匹配精确。用取反字符集代替点号。例如我们用如下正则表达式<<^([^,\r\n]*,){11}P>>,这样可以使失败回溯的次数下降到11次。

另一种方案是使用原子组。

原子组的目的是使正则引擎失败的更快一点。因此可以有效的阻止海量回溯。原子组的语法是<<(?>正则表达式)>>。位于(?>)之间的所有正则表达式都会被认为是一个单一的正则符号。一旦匹配失败,引擎将会回溯到原子组前面的正则表达式部分。前面的例子用原子组可以表达成<<^(?>(.*?,){11})P>>。一旦第十二个字段匹配失败,引擎回溯到原子组前面的<<^>>。

 

14.  向前查看与向后查看

Perl 5 引入了两个强大的正则语法:“向前查看”和“向后查看”。他们也被称作“零长度断言”。他们和锚定一样都是零长度的(所谓零长度即指该正则表达式不消耗被匹配的字符串)。不同之处在于“前后查看”会实际匹配字符,只是他们会抛弃匹配只返回匹配结果:匹配或不匹配。这就是为什么他们被称作“断言”。他们并不实际消耗字符串中的字符,而只是断言一个匹配是否可能。

几乎本文讨论的所有正则表达式的实现都支持“向前向后查看”。唯一的一个例外是Javascript只支持向前查看。

·        肯定和否定式的向前查看

如我们前面提过的一个例子:要查找一个q,后面没有紧跟一个u。也就是说,要么q后面没有字符,要么后面的字符不是u。采用否定式向前查看后的一个解决方案为<<q(?!u)>>。否定式向前查看的语法是<<(?!查看的内容)>>。

肯定式向前查看和否定式向前查看很类似:<<(?=查看的内容)>>。

如果在“查看的内容”部分有组,也会产生一个向后引用。但是向前查看本身并不会产生向后引用,也不会被计入向后引用的编号中。这是因为向前查看本身是会被抛弃掉的,只保留匹配与否的判断结果。如果你想保留匹配的结果作为向后引用,你可以用<<(?=(regex))>>来产生一个向后引用。

·        肯定和否定式的先后查看

向后查看和向前查看有相同的效果,只是方向相反

否定式向后查看的语法是:<<(?<!查看内容)>>

肯定式向后查看的语法是:<<(?<=查看内容)>>

我们可以看到,和向前查看相比,多了一个表示方向的左尖括号。

例:<<(?<!a)b>>将会匹配一个没有“a”作前导字符的“b”。

值得注意的是:向前查看从当前字符串位置开始对“查看”正则表达式进行匹配;向后查看则从当前字符串位置开始先后回溯一个字符,然后再开始对“查看”正则表达式进行匹配。

 

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

让我们看一个简单例子。

把正则表达式<<q(?!u)>>应用到字符串“Iraq”。正则表达式的第一个符号是<<q>>。正如我们知道的,引擎在匹配<<q>>以前会扫过整个字符串。当第四个字符“q”被匹配后,“q”后面是空字符(void)。而下一个正则符号是向前查看。引擎注意到已经进入了一个向前查看正则表达式部分。下一个正则符号是<<u>>,和空字符不匹配,从而导致向前查看里的正则表达式匹配失败。因为是一个否定式的向前查看,意味着整个向前查看结果是成功的。于是匹配结果“q”被返回了。

我们在把相同的正则表达式应用到“quit”。<<q>>匹配了“q”。下一个正则符号是向前查看部分的<<u>>,它匹配了字符串中的第二个字符“i”。引擎继续走到下个字符“i”。然而引擎这时注意到向前查看部分已经处理完了,并且向前查看已经成功。于是引擎抛弃被匹配的字符串部分,这将导致引擎回退到字符“u”。

因为向前查看是否定式的,意味着查看部分的成功匹配导致了整个向前查看的失败,因此引擎不得不进行回溯。最后因为再没有其他的“q”和<<q>>匹配,所以整个匹配失败了。

为了确保你能清楚地理解向前查看的实现,让我们把<<q(?=u)i>>应用到“quit”。<<q>>首先匹配“q”。然后向前查看成功匹配“u”,匹配的部分被抛弃,只返回可以匹配的判断结果。引擎从字符“i”回退到“u”。由于向前查看成功了,引擎继续处理下一个正则符号<<i>>。结果发现<<i>>和“u”不匹配。因此匹配失败了。由于后面没有其他的“q”,整个正则表达式的匹配失败了。

 

·        更进一步理解正则表达式引擎内部机制

让我们把<<(?<=a)b>>应用到“thingamabob”。引擎开始处理向后查看部分的正则符号和字符串中的第一个字符。在这个例子中,向后查看告诉正则表达式引擎回退一个字符,然后查看是否有一个“a”被匹配。因为在“t”前面没有字符,所以引擎不能回退。因此向后查看失败了。引擎继续走到下一个字符“h”。再一次,引擎暂时回退一个字符并检查是否有个“a”被匹配。结果发现了一个“t”。向后查看又失败了。

向后查看继续失败,直到正则表达式到达了字符串中的“m”,于是肯定式的向后查看被匹配了。因为它是零长度的,字符串的当前位置仍然是“m”。下一个正则符号是<<b>>,和“m”匹配失败。下一个字符是字符串中的第二个“a”。引擎向后暂时回退一个字符,并且发现<<a>>不匹配“m”。

在下一个字符是字符串中的第一个“b”。引擎暂时性的向后退一个字符发现向后查看被满足了,同时<<b>>匹配了“b”。因此整个正则表达式被匹配了。作为结果,正则表达式返回字符串中的第一个“b”。

·        向前向后查看的应用

我们来看这样一个例子:查找一个具有6位字符的,含有“cat”的单词。

首先,我们可以不用向前向后查看来解决问题,例如:

<< cat\w{3}|\wcat\w{2}|\w{2}cat\w|\w{3}cat>>

足够简单吧!但是当需求变成查找一个具有6-12位字符,含有“cat”,“dog”或“mouse”的单词时,这种方法就变得有些笨拙了。

我们来看看使用向前查看的方案。在这个例子中,我们有两个基本需求要满足:一是我们需要一个6位的字符,二是单词含有“cat”。

满足第一个需求的正则表达式为<<\b\w{6}\b>>。满足第二个需求的正则表达式为<<\b\w*cat\w*\b>>。

把两者结合起来,我们可以得到如下的正则表达式:

     <<(?=\b\w{6}\b)\b\w*cat\w*\b>>

具体的匹配过程留给读者。但是要注意的一点是,向前查看是不消耗字符的,因此当判断单词满足具有6个字符的条件后,引擎会从开始判断前的位置继续对后面的正则表达式进行匹配。

最后作些优化,可以得到下面的正则表达式:

<<\b(?=\w{6}\b)\w{0,3}cat\w*>>

 

15.  正则表达式中的条件测试

条件测试的语法为<<(?ifthen|else)>>。“if”部分可以是向前向后查看表达式。如果用向前查看,则语法变为:<<(?(?=regex)then|else)>>,其中else部分是可选的。

如果if部分为true,则正则引擎会试图匹配then部分,否则引擎会试图匹配else部分。

需要记住的是,向前先后查看并不实际消耗任何字符,因此后面的then与else部分的匹配时从if测试前的部分开始进行尝试。

 

16.  为正则表达式添加注释

在正则表达式中添加注释的语法是:<<(?#comment)>>

例:为用于匹配有效日期的正则表达式添加注释:

 (?#year)(19|20)\d\d[- /.](?#month)(0[1-9]|1[012])[- /.](?#day)(0[1-9]|[12][0-9]|3[01])

Tags: 正则表达式

正则表达式收藏(一)之使用说明

一、简介

正则表达式这个名词,相信很多人都听说过,这个名词最早起源于1956 年, 一位叫 Stephen Kleene 的美国数学家在 McCulloch 和 Pitts 早期工作的基础上,发表了一篇标题为“神经网事件的表示法”的论文,引入了正则表达式的概念。正则表达式就是用来描述他称为“正则集的代数”的表达式,因此采用“正则表达式”这个术语。

随后,发现可以将这一工作应用于使用Ken Thompson 的计算搜索算法的一些早期研究,Ken Thompson是Unix 的主要发明人。正则表达式的第一个实用应用程序就是 Unix 中的qed 编辑器。

Q: 正则表达式,能够为我们做什么呢?

A: 基于文本的编辑器和搜索工具中的一个重要部分。正则表达式可以让用户通过使用一系列的特殊字符构建匹配模式,然后把匹配模式与数据文件、程序输入以及WEB页面的表单输入等目标对象进行比较,根据比较对象中是否包含匹配模式,执行相应的程序。

下面我们就一步一步的结合它的语法,来介绍正则表达式的使用。

二、初次接触正则表达式

我们先来了解正则表达式的一些基本概念。正则表达式作为一种表示语言,其定义了自己的一套描述方式,来描述各种各样的字符类。下面摘取msdn中的一段定义。(ms-help://MS.VSCC/MS.MSDNVS.2052/cpgenref/html/cpconcharacterclasses.htm)

字符转义表
字符类
含义

.
与除 \n 以外的任何字符匹配。如果通过 Singleline 选项(请参阅正则表达式选项)进行了修改,则句点字符与任何字符匹配。

[aeiou]
与指定字符集中包含的任何单个字符匹配。

[^aeiou]
与不在指定字符集中的任何单个字符匹配。

[0-9a-fA-F]
使用连字号 (–) 允许指定连续字符范围。

\p{name}
与 name 指定的命名字符类中的任何字符匹配。支持的名称为 Unicode 组和块范围。例如 Ll£?Nd£?Z£?IsGreek£?IsBoxDrawing。

\P{name}
与在 {name} 中指定的组和块范围中未包含的文本匹配。

\w
与任何单词字符匹配。等效于 Unicode 字符类别
[\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}]。如果通过 ECMAScript 选项指定了符合 ECMAScript 的行为,则 \w 等同于 [a-zA-Z_0-9]。

\W
与任何非单词字符匹配。等效于 Unicode 类别 [^\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}]。如果通过 ECMAScript 选项指定了符合 ECMAScript 的行为,则 \W 等同于 [^a-zA-Z_0-9]。

\s
与任何空白字符匹配。等效于 Unicode 字符类别 [\f\n\r\t\v\x85\p{Z}]。如果通过 ECMAScript 选项指定了符合 ECMAScript 的行为,则 \s 等同于 [ \f\n\r\t\v]。

\S
与任何非空白字符匹配。等效于 Unicode 字符类别 [^\f\n\r\t\v\x85\p{Z}]。如果通过 ECMAScript 选项指定了符合 ECMAScript 的行为,则 \S 等同于 [^ \f\n\r\t\v]。

\d
与任何十进制数字匹配。与 Unicode 的 \p{Nd} 和非 Unicode 的 [0-9] 以及 ECMAScript 行为一样。

\D
与任何非数字匹配。与 Unicode 的 \P{Nd} 和非 Unicode 的 [^0-9] 以及 ECMAScript 行为一样。


上表列举了,正则表达式中最最基本的语法定义,了解这些,我们已经可以定义一些简单的规则了,例如:

1. 匹配所有的字符

当然是什么都不用写(@_@)

2. 匹配所有的英文字符

a) \w

b) [a-zA-Z_0-9]

3. 匹配十进制数字

a) \d

b) [0-9]

看上面的例子,是不是觉得很简单呢,不过,到目前为止,这样写出来的规则,还有一个很大的缺陷,就是没有声明匹配字符的个数?

Q: 我希望要匹配的字符为5个英文字母

A: ???

光了解上面的知识是,无法解决这个的L。那正则表达式中是如何解决这个问题的呢,我们来看下面这个表:

(ms-help://MS.VSCC/MS.MSDNVS.2052/cpgenref/html/cpconquantifiers.htm)

限定符表
限定符
说明

*
指定零个或更多个匹配;例如 \w* 或 (abc)*。与 {0,} 相同。

+
指定一个或多个匹配;例如 \w+ 或 (abc)+。与 {1,} 相同。

?
指定零个或一个匹配;例如 \w? 或 (abc)?。与 {0,1} 相同。

{n}
指定恰好 n 个匹配;例如 (pizza){2}。

{n,}
指定至少 n 个匹配;例如 (abc){2,}。

{n,m}
指定至少 n 个但不多于 m 个匹配。

*?
指定尽可能少地使用重复的第一个匹配 (lazy *)。

+?
指定尽可能少地使用重复但至少使用一次 (lazy +)。

??
指定使用零次重复(如有可能)或一次重复 (lazy ?)。

{n}?
等效于 {n} (lazy {n})。

{n,}?
指定尽可能少地使用重复,但至少使用 n 次 (lazy {n,})。

{n,m}?
指定介于 n 次和 m 次之间、尽可能少地使用重复 (lazy {n,m})。


上表中列出了,正则表达式的限定方式,配合这些字符的使用,我们就可以很方便的编写更为强劲的正则表达式了。

例如:

1. 匹配零个或多个所有的字符

*

2. 匹配一个或多个所有字符

+

3. 匹配零个或多个所有的英文字符

\w*

4. 匹配一个或多个所有的英文字符

[a-zA-Z0-9]+

5. 匹配3个十进制数字

\d{3}

6. 匹配最少3个十进制数字

\d{3,}

7. 匹配3个到6个十进制数字

\d{3,6}

现在我们可以解答上面问题了:

Q: 我希望要匹配的字符为5个英文字母

A: \w{5}

很高兴,我们已解决了上面的问题,不过,新的问题总是在不断的出现。我如何限制匹配字符出现在哪里呢?

Q: 我希望匹配以doc开头的字符串

A: ???

为了解决这个问题,我们先来看看这个表:

(ms-help://MS.VSCC/MS.MSDNVS.2052/cpgenref/html/cpconatomiczero-widthassertions.htm)

原子零宽度断言
断言
说明

^
指定匹配必须出现在字符串的开头或行的开头。有关更多信息,请参阅正则表达式选项中的 Multiline 选项。

$
指定匹配必须出现在以下位置:字符串结尾、字符串结尾的 \n 之前或行的结尾。有关更多信息,请参阅正则表达式选项中的 Multiline 选项。

\A
指定匹配必须出现在字符串的开头(忽略 Multiline 选项)。

\Z
指定匹配必须出现在字符串的结尾或字符串结尾的 \n 之前(忽略 Multiline 选项)。

\z
指定匹配必须出现在字符串的结尾(忽略 Multiline 选项)。

\G
指定匹配必须出现在当前搜索开始的位置(此位置通常是上一次搜索结束位置之后的第一个字符)。例如,请考虑一个由分离的字符组组成的串联字符串,其中每一组的长度都为 n 个字符。在每个字符组中搜索匹配时,如果正则表达式在 0、n、2n、3n 等字符位置找到匹配,则该正则表达式成功。仅当匹配出现在定位组边界上时才会成功。

\b
指定匹配必须出现在 \w(字母数字)和 \W(非字母数字)字符之间的边界上。匹配必须出现在单词边界上,即出现在由空格分隔的单词中第一个或最后一个字符上。

\B
指定匹配不得出现在 \b 边界上。


相信大家都注意到了,在这个表中第一个断言字符就是我们需要的@_@.

例如,^ 指定当前位置在行或字符串的开头。因此,正则表达式 ^FTP 只会返回那些在行的开头出现的字符串“FTP”的匹配项。

看来上面碰到的问题,又可以解决了,让我们一起来解决上面的问题:

Q: 我希望匹配以doc开头的字符串

A: ^doc

以上我们初步了解了什么是正则表达式,已经了解其最基本的语法,当作热身@_@,接下来,才正式进入主题,我们会从第二篇开始深入探讨正则表达式的使用。
在前一篇文章中,介绍了一些初步的正则表达式的基本概念,相信很多人对正则表达式的基本知识有所了解,接下来,我们结合一些实际的编程示例来掩饰说明正则表达式的作用。

首先,我们先看几个实际的例子:

1. 验证输入字符是否全部为英文字符

javascript:

var ex = "^\\w+$";

var re = new RegExp(ex,"i");

return re.test(str);

VBScript

Dim regEx,flag,ex

ex = "^\w+$"

Set regEx = New RegExp

regEx.IgnoreCase = True

regEx.Global = True

regEx.Pattern = ex

flag = regEx.Test( str )

C#

System.String ex = @"^\w+$";

System.Text.RegularExpressions.Regex reg = new Regex( ex ); bool flag = reg.IsMatch( str );

2. 验证邮件格式

C#

System.String ex = @"^\w+@\w+\.\w+$";

System.Text.RegularExpressions.Regex reg = new Regex( ex );

bool flag = reg.IsMatch( str );

3. 更改日期的格式(用 dd-mm-yy 的日期形式代替 mm/dd/yy 的日期形式)

C#

String MDYToDMY(String input)

{

return Regex.Replace(input,

"\\b(?<month>\\d{1,2})/(?<day>\\d{1,2})/(?<year>\\d{2,4})\\b",

"${day}-${month}-${year}");

}

4. 从 URL 提取协议和端口号

C#

String Extension(String url)

{

Regex r = new Regex(@"^(?<proto>\w+)://[^/]+?(?<port>:\d+)?/",

RegexOptions.Compiled);

return r.Match(url).Result("${proto}${port}");

}

这里的例子可能是我们在网页开发中,通常会碰到的一些正则表达式,尤其在第一个例子中,给出了使用javascript,vbScript,C#等不同语言的实现方式,大家不难看出,对于不同的语言来说,正则表达式没有区别,只是正则表达式的实现类不同而已。而如何发挥正则表达式的公用,也要看实现类的支持。

(摘自msdn: Microsoft .NET 框架 SDK 提供大量的正则表达式工具,使您能够高效地创建、比较和修改字符串,以及迅速地分析大量文本和数据以搜索、移除和替换文本模式。ms-help://MS.VSCC/MS.MSDNVS.2052/cpgenref/html/cpconregularexpressionslanguageelements.htm)

下面我们逐个来分析这些例子:

1-2,这两个例子很简单,只是简单的验证字符串是否符合正则表达式规定的格式,其中使用的语法,在第一篇文章中都已经介绍过了,这里做一下简单的描述。

第1个例子的表达式: ^\w+$

^ -- 表示限定匹配开始于字符串的开始

\w – 表示匹配英文字符

+ -- 表示匹配字符出现1次或多次

$ -- 表示匹配字符到字符串结尾处结束

验证形如asgasdfs的字符串

第2个例子的表达式: ^\w+@\w+.\w+$

^ -- 表示限定匹配开始于字符串的开始

\w – 表示匹配英文字符

+ -- 表示匹配字符出现1次或多次

@ -- 匹配普通字符@

\. – 匹配普通字符.(注意.为特殊字符,因此要加上\转译)

$ -- 表示匹配字符到字符串结尾处结束

验证形如dragontt@sina.com的邮件格式





第3 个例子中,使用了替换,因此,我们还是先来看看正则表达式中替换的定义:

(ms-help://MS.VSCC/MS.MSDNVS.2052/cpgenref/html/cpconsubstitutions.htm)

替换
字符
含义

$123
替换由组号 123(十进制)匹配的最后一个子字符串。

${name}
替换由 (?<name> ) 组匹配的最后一个子字符串。

$$
替换单个“$”字符。

$&
替换完全匹配本身的一个副本。

$`
替换匹配前的输入字符串的所有文本。

$'
替换匹配后的输入字符串的所有文本。

$+
替换最后捕获的组。

$_
替换整个输入字符串。


分组构造
(ms-help://MS.VSCC/MS.MSDNVS.2052/cpgenref/html/cpcongroupingconstructs.htm)

分组构造
定义

( )
捕获匹配的子字符串(或非捕获组;有关更多信息,请参阅正则表达式选项中的 ExplicitCapture 选项。)使用 () 的捕获根据左括号的顺序从 1 开始自动编号。捕获元素编号为零的第一个捕获是由整个正则表达式模式匹配的文本。

(?<name> )
将匹配的子字符串捕获到一个组名称或编号名称中。用于 name 的字符串不能包含任何标点符号,并且不能以数字开头。可以使用单引号替代尖括号,例如 (?'name')。

(?<name1-name2> )
平衡组定义。删除先前定义的 name2 组的定义并在 name1 组中存储先前定义的 name2 组和当前组之间的间隔。如果未定义 name2 组,则匹配将回溯。由于删除 name2 的最后一个定义会显示 name2 的先前定义,因此该构造允许将 name2 组的捕获堆栈用作计数器以跟踪嵌套构造(如括号)。在此构造中,name1 是可选的。可以使用单引号替代尖括号,例如 (?'name1-name2')。

(?: )
非捕获组。

(?imnsx-imnsx: )
应用或禁用子表达式中指定的选项。例如,(?i-s: ) 将打开不区分大小写并禁用单行模式。有关更多信息,请参阅正则表达式选项。

(?= )
零宽度正预测先行断言。仅当子表达式在此位置的右侧匹配时才继续匹配。例如,\w+(?=\d) 与后跟数字的单词匹配,而不与该数字匹配。此构造不会回溯。

(?! )
零宽度负预测先行断言。仅当子表达式不在此位置的右侧匹配时才继续匹配。例如,\b(?!un)\w+\b 与不以 un 开头的单词匹配。

(?<= )
零宽度正回顾后发断言。仅当子表达式在此位置的左侧匹配时才继续匹配。例如,(?<=19)99 与跟在 19 后面的 99 的实例匹配。此构造不会回溯。

(?<! )
零宽度负回顾后发断言。仅当子表达式不在此位置的左侧匹配时才继续匹配。

(?> )
非回溯子表达式(也称为贪婪子表达式)。该子表达式仅完全匹配一次,然后就不会逐段参与回溯了。(也就是说,该子表达式仅与可由该子表达式单独匹配的字符串匹配。)




我们还是先简单的了解一下这两个概念:

分组构造:

最基本的构造方式就是(),在左右括号中括起来的部分,就是一个分组;

更进一步的分组就是形如:(?<name> )的分组方式,这种方式与第一种方式的不同点,就是对分组的部分进行了命名,这样就可以通过该组的命名来获取信息;

(还有形如(?= )等等的分组构造,我们这篇的例子中也没有使用到,下次我们在来介绍)

替换:

上面提到了两种基本的构造分组方式()以及(?<name> ),通过这两种分组方式,我们可以得到形如$1,${name}的匹配结果。



这样说,可能概念上还是有些模糊,我们还是结合上面的例子来说:

第三个例子的正则表达式为:\\b(?<month>\\d{1,2})/(?<day>\\d{1,2})/(?<year>\\d{2,4})\\b

(解释一下,为什么这里都是\\一起用:这里是C#的例子,在C#语言中\是转译字符,要想字符串中的\不转译,就需要使用\\或者在整个字符串的开始加上@标记,即上面等价与

@”\b(?<month>\d{1,2})/(?<day>\d{1,2})/(?<year>\d{2,4}\b”)

\b -- 是一种特殊情况。在正则表达式中,除了在 [] 字符类中表示退格符以外,\b 表示字边界(在 \w 和 \W 字符之间)。在替换模式中,\b 始终表示退格符

(?<month>\d{1,2}) – 构造一个名为month的分组,这个分组匹配一个长度为1-2的数字

/ -- 匹配普通的/字符

(?<day>\d{1,2}) --构造一个名为day的分组,这个分组匹配一个长度为1-2的数字

/ -- 匹配普通的/字符

(?<year>\d{2,4}\b”) --构造一个名为year的分组,这个分组匹配一个长度为2-4的数字



这里还不能够看出这些分组的作用,我们接着看这一句

${day}-${month}-${year}

${day} – 获得上面构造的名为day的分组匹配后的信息

- -- 普通的-字符

${month} --获得上面构造的名为month的分组匹配后的信息

- -- 普通的-字符

${year} --获得上面构造的名为year的分组匹配后的信息



举例来说:

将形如04/02/2003的日期使用例3种的方法替换

(?<month>\d{1,2}) 分组将匹配到04由${month}得到这个匹配值

(?<day>\d{1,2}) 分组将匹配到02由${day}得到这个匹配值

(?<year>\d{1,2}) 分组将匹配到2003由${year}得到这个匹配值

了解了这个例子后,我们在来看第4个例子就很简单了。



第4个例子的正则

^(?<proto>\w+)://[^/]+?(?<port>:\d+)?/

^ -- 表示限定匹配开始于字符串的开始

(?<proto>\w+) – 构造一个名为proto的分组,匹配一个或多个字母

: -- 普通的:字符

// -- 匹配两个/字符

[^/] – 表示这里不允许是/字符

+? – 表示指定尽可能少地使用重复但至少使用一次匹配

(?<port>:\d+) – 构造一个名为port的分组,匹配形如:2134(冒号+一个或多个数字)

? – 表示匹配字符出现0次或1次

/ -- 匹配/字符



最后通过${proto}${port}来获取两个分组构造的匹配内容

(有关Regex对象的用法,参考

ms-help://MS.VSCC/MS.MSDNVS.2052/cpref/html/frlrfSystemTextRegularExpressionsRegexMembersTopic.htm)



好了,本次介绍的几个例子,也讲得差不多了,希望大家有所收获,下次,在就一些特殊的要求,进一步探讨正则表达式的实现。
前面的文章中,介绍了正则表达式的基本语法,以及一些简单的例子。但这些并不是我们会遇到的全部问题,有些时候我们不得不编写一些较为复杂的正则表达式来解决我们的实际问题。

这里,我先提几个问题,然后,我们逐个运用正则表达式的知识来解决。

1. 符合两种条件之一,都成立,例如:是纯数字或者纯字符

123(true),hello(true),234.test23(false)

2. 要得到不以数字开头的字符组合

如:How2234do>you234do,希望得到How和you而不是do,do

3. 得到以数字开头的字符组合

上例中,得到do和do

4. 要得到不以数字结尾的字符组合

还是上面的情况,要得到的是Ho,do,yo,do

5. 得到以数字结尾的字符组合

同上例,得到Ho,do,yo,do

6. 不允许字符中ab同时出现

例:nihaoma(true),above(false),agoodboy(true)



下面我们开始着手解决这些问题:

第一个:符合两种条件之一,都成立

这种要求可能代表着一种普遍的要求,我们先来看看这个表

替换构造
替换构造
定义

|
与由|(垂直条)字符分隔的术语中的任何一个术语匹配;例如 cat|dog|tiger。使用最左侧的成功匹配。

(?(expression)yes|no)
如果表达式在此位置匹配,则与“yes”部分匹配;否则,与“no”部分匹配。“no”部分可省略。表达式可以是任何有效的表达式,但它将变为零宽度断言,因此该语法等效于 (?(?=expression)yes|no)。请注意,如果表达式是命名组的名称或捕获组编号,则替换构造将解释为捕获测试(在本表的下一行对此进行了描述)。若要避免在这些情况下产生混淆,则可以显式拼出内部 (?=expression)。

(?(name)yes|no)
如果命名捕获字符串有匹配,则与“yes”部分匹配;否则,与“no”部分匹配。“no”部分可省略。如果给定的名称不与此表达式中使用的捕获组的名称或编号对应,则替换构造将解释为表达式测试(在本表的上一行进行了描述)。


(ms-help://MS.VSCC/MS.MSDNVS.2052/cpgenref/html/cpconalternationconstructs.htm)

在这个表中,我们看到,正则中为了解决这一类问题,定义了|来表示或者的关系,就好像常见的或运算符一样,现在我们来看看如何利用|来解决我们的问题。

1. 先为可选择的表达式撰写表达式:

a) 纯数字 – [0-9]*

b) 纯字母 – [a-zA-Z]*

2. 将可选条件用|连接起来就是我们所需的

^[0-9]*$|^[a-zA-Z]*$

(这里我特别对两个条件加上了^和$限定符,这在验证字符串是否完全符合要求时,是十分必要的,如果不加这两个限定符,有兴趣的朋友可以自己试一下效果。



后面四个问题,其实是一类的,所以我们把它们放在一起处理。接下来我们来解决第二到第四个问题:

首先,我们回顾一下上次介绍的分组构造:

(?= )
零宽度正预测先行断言。仅当子表达式在此位置的右侧匹配时才继续匹配。例如,\w+(?=\d) 与后跟数字的单词匹配,而不与该数字匹配。此构造不会回溯。

(?! )
零宽度负预测先行断言。仅当子表达式不在此位置的右侧匹配时才继续匹配。例如,\b(?!un)\w+\b 与不以 un 开头的单词匹配。

(?<= )
零宽度正回顾后发断言。仅当子表达式在此位置的左侧匹配时才继续匹配。例如,(?<=19)99 与跟在 19 后面的 99 的实例匹配。此构造不会回溯。

(?<! )
零宽度负回顾后发断言。仅当子表达式不在此位置的左侧匹配时才继续匹配。


可以看到,这个表的这四种规则,正好可以解决我们的问题。

@_@先解决我们的问题再说:

第二例:要得到不以数字开头的字符组合

(?<!\d)[a-zA-Z]{2,}

(?<!\d) -- 限定字符的开头不为数字才匹配

[a-zA-Z]{2,} – 描述匹配2个以上的字母

(注:这是取巧的做法,因为,按照我们的逻辑How2234do>you234do中的两个do的o字母也是符合的,不过,这不是我们想要的,当然还有其他的解决办法,可以根据实际的情况来处理,这里是为了讲解这个方法@_@)

第三例:得到以数字开头的字符组合

(?<=\d)[a-zA-Z]+

(?<=\d) – 限定为数字开头的字符才匹配

[a-zA-Z]+ -- 描述匹配1个或多个字母

第四例:要得到不以数字结尾的字符组合

[a-zA-Z]+(?!\d)

[a-zA-Z]+ -- 描述匹配1个或多个字母

(?!\d) – 限定不为数字结尾的字母才匹配

第五例:得到以数字结尾的字符组合

[a-zA-Z]+(?=\d)

[a-zA-Z]+ -- 描述匹配1个或多个字母

(?=\d) – 限定为数字结尾的字母才匹配



第六例:不允许字符中ab同时出现

^(?!.*?ab).*$

(?!.*?ab) – 限定不允许出现ab相连的字符

.* -- 任意字符

表达式

语法

说明

任一字符

.

匹配除换行符外的任何一个字符。

最多 0 项或更多

*

匹配前面表达式的 0 个或更多搜索项。

最多一项或更多

+

匹配前面表达式的至少一个搜索项。

最少 0 项或更多

@

匹配前面表达式的 0 个或更多搜索项,匹配尽可能少的字符。

最少一项或更多

#

匹配前面表达式的一个或更多搜索项,匹配尽可能少的字符。

重复 n

^n

匹配前面表达式的 n 个搜索项。例如,[0-9]^4 匹配任意 4 位数字的序列。

字符集

[]

匹配 [] 内的任何一个字符。要指定字符的范围,请列出由短划线 (-) 分隔的起始字符和结束字符,如 [a-z] 中所示。

不在字符集中的字符

[^...]

匹配跟在 ^ 之后的不在字符集中的任何字符。

行首

^

将匹配定位到行首。

行尾

$

将匹配定位到行尾。

词首

< 

仅当词在文本中的此位置开始时才匹配。

词尾

> 

仅当词在文本中的此位置结束时才匹配。

分组

()

将子表达式分组。

|

匹配 OR 符号 (|) 之前或之后的表达式。). 最常用在分组中。例如,(sponge|mud) bath 匹配“sponge bath”“mud bath”

转义符

\

匹配跟在反斜杠 (\) 后的字符。这使您可以查找在正则表达式表示法中使用的字符,如 { ^。例如,\^ 搜索 ^ 字符。

带标记的表达式

{}

标记括号内的表达式所匹配的文本。

n 个带标记的文本

\n

查找替换表达式中,指示第 n 个带标记的表达式所匹配的文本,其中 n 是从 1 9 的数字。

替换表达式中,\0 插入整个匹配的文本。

右对齐字段

\(w,n)

替换表达式中,将字段中第 n 个带标记的表达式右对齐至少 w 字符宽。

左对齐字段

\(-w,n)

替换表达式中,将字段中第 n 个带标记的表达式左对齐至少 w 字符宽。

禁止匹配

~(X)

X 出现在表达式中的此位置时禁止匹配。例如,real~(ity)    匹配“realty”“really”中的“real”,而不匹配“reality”中的“real”

字母数字字符

:a

匹配表达式
([a-zA-Z0-9])

字母字符

:c

匹配表达式
([a-zA-Z])

十进制数

:d

匹配表达式
([0-9])

十六进制数

:h

匹配表达式
([0-9a-fA-F]+)

标识符

:i

匹配表达式
([a-zA-Z_$][a-zA-Z0-9_$]*)

有理数

:n

匹配表达式
(([0-9]+.[0-9]*)| ([0-9]*.[0-9]+)| ([0-9]+)).

带引号的字符串

:q

匹配表达式 (("[^"]*")| ('[^']*'))

字母字符串

:w

匹配表达式
([a-zA-Z]+)

十进制整数

:z

匹配表达式
([0-9]+)

转义符

\e

Unicode U+001B

Bell

\g

Unicode U+0007

退格符

\h

Unicode U+0008

换行符

\n

匹配与平台无关的换行符。在替换表达式中,插入换行符。

制表符

\t

匹配制表符,Unicode U+0009

Unicode 字符

\x#### \u####

匹配 Unicode 值给定的字符,其中 #### 是十六进制数。可以用 ISO 10646 代码点或两个提供代理项对的值的 Unicode 代码点指定基本多语种平面(即一个代理项)外的字符。

 

下表列出按标准 Unicode 字符属性进行匹配的语法。两个字母的缩写词与 Unicode 字符属性数据库中所列的一样。可将这些指定为字符集的一部分。例如,表达式 [:Nd:Nl:No] 匹配任何种类的数字。

表达式

语法

说明

大写字母

:Lu

匹配任何一个大写字母。例如,:Luhe 匹配“The”但不匹配“the”

小写字母

:Ll

匹配任何一个小写字母。例如,:Llhe 匹配“the”但不匹配“The”

词首大写字母

:Lt

匹配将大写字母和小写字母结合的字符,例如,Nj Dz

修饰符字母

:Lm

匹配字母或标点符号,例如逗号、交叉重音符和双撇号,用于表示对前一字母的修饰。

其他字母

:Lo

匹配其他字母,如哥特体字母 ahsa

十进制数

:Nd

匹配十进制数(如 0-9)和它们的双字节等效数。

字母数字

:Nl

匹配字母数字,例如罗马数字和表意数字零。

其他数字

:No

匹配其他数字,如旧斜体数字一。

开始标点符号

:Ps

匹配开始标点符号,例如左方括号和左大括号。

结束标点符号

:Pe

匹配结束标点符号,例如右方括号和右大括号。

左引号

:Pi

匹配左双引号。

右引号

:Pf

匹配单引号和右双引号。

破折号

:Pd

匹配破折号标记。

连接符号

:Pc

匹配下划线标记。

其他标点符号

:Po

匹配逗号 (,)?"!@#%&*\、冒号 (:)、分号 (;)' /

空白分隔符

:Zs

匹配空白。

行分隔符

:Zl

匹配 Unicode 字符 U+2028

段落分隔符

:Zp

匹配 Unicode 字符 U+2029

无间隔标记

:Mn

匹配无间隔标记。

组合标记

:Mc

匹配组合标记。

封闭标记

:Me

匹配封闭标记。

数学符号

:Sm

匹配 +=~| < >

货币符号

:Sc

匹配 $ 和其他货币符号。

修饰符号

:Sk

匹配修饰符号,如抑扬音、抑音符号和长音符号。

其他符号

:So

匹配其他符号,如版权符号、段落标记和度数符号。

其他控制

:Cc

匹配行尾。

其他格式

:Cf

格式化控制字符,例如双向控制字符。

代理项

:Cs

匹配代理项对的一半。

其他私用

:Co

匹配私用区域的任何字符。

其他未分配的字符

:Cn

匹配未映射到 Unicode 字符的字符。

除标准 Unicode 字符属性外,还可以指定下列附加属性。可将这些属性指定为字符集的一部分。

表达式

语法

说明

Alpha

:Al

匹配任何一个字符。例如,:Alhe 匹配“The”“then”“reached”等单词。

数字

:Nu

匹配任何一个数或数字。

标点符号

:Pu

匹配任何一个标点符号,如 ?@' 等等。

空白

:Wh

匹配所有类型的空格,包括印刷和表意文字的空格。

Bidi

:Bi

匹配诸如阿拉伯文和希伯来文这类从右向左书写的字符。

朝鲜文

:Ha

匹配朝鲜文和组合朝鲜文字母。

平假名

:Hi

匹配平假名字符。

片假名

:Ka

匹配片假名字符。

表意文字/汉字/日文汉字

:Id

匹配表意文字字符,如汉字和日文汉字

基本语法

模式

说明

.

匹配除换行符(\n)之外的任何单个字符. 要匹配包括 '\n' 在内的任何字符, 可以使用 [.\n] 模式.

\

转义字符, 用于转义紧跟的字符. 详情请参考转义字符表.

[...]

定义一个字符类, 匹配方括号内的任意一个字符.
: [abc] 可以匹配单个字符 a, b c.

[^...]

定义一个非匹配字符类的开始处, 它表示否定该字符类, 即匹配不在方括号中出现的任何字符.
: [^abc] 可以匹配 e, 7, z 等除 a, b c 之外的字符.

^

如果 ^ 出现在正则表达式最前边, 它匹配输入字符串的开头.
: ^[abc] 匹配输入字符串开头的 a, b c , about us, be it, can you?.

$

放在正则表达式的最后, 匹配输入字符串的末端.
: [0-9]$ 匹配输入字符串末端的一个数字字符, last 9, add 1.

|

""分隔符, 分隔多个表达式, 只须匹配其中一个.
: th(is|at|ese|ose) 可以匹配 this, that, these those.

-

在字符类中, 指定一个字符范围.
: [0-9] 匹配 0 9 的数字.

?

匹配前面的子表达式零次或一次. ? 等价于 {0,1} .
: do(es)? 可以匹配 do does.

+

匹配前面的子表达式一次或多次. + 等价于 {1,} .
: zo+ 能匹配 zo 以及 zoo 或者 zoooo, 但不能匹配 z .

*

匹配前面的子表达式零次或多次. * 等价于 {0,} .
: zo* 能匹配 z 以及 zoo .

{n}

匹配前面的子表达式确定的 n . n 是一个非负整数.
: o{2} 不能匹配 Bob 中的 o , 但是能匹配 food 中的 oo .

{n,}

匹配前面的子表达式至少 n . n 是一个非负整数. e{1,} 等价于 e+ , e{0,} 则等价于 e* .
: e{2,} 不能匹配 Bed 中的 e , 但是能匹配 feel feeeeel 中所有的 e .

{n,m}

匹配前面的子表达式最少 n 次且最多 m . n<=m, m n 均为非负整数. 在逗号和两个数字之间不能有空格. o{0,1} 等价于 o? .
: o{1,3} 可以匹配 fooooood 中的前三个 o .

??
+?
*?
{n}?
{n,}?
{n,m}?

?, +, *, {n}, {n,}, {n,m} 的非贪婪匹配版本, 非贪婪匹配在匹配时会尽可能匹配较少的字符.
: 输入字符串为 <abc><def>
使用非贪婪匹配 <.*?> 会匹配 <abc> .
使用贪婪匹配 <.*> 会匹配整个 <abc><def> .

(pattern)

表达式分组操作符. 用于分隔子表达式和返回部分匹配结果. 返回的结果可以在替换操作的时候用 $1 - $10 表示.
: (\d+,)*\d+ 可以匹配逗号分隔的数字字符串, 41 1,23,456 .

(?:pattern)

非获取匹配分组, 匹配 pattern 但不返回匹配结果, 这样可以节省资源, 也不容易与获取匹配的结果混淆.

(?=pattern)

肯定正查(Positive Lookahead). 作用类似 $, 匹配任何后缀有符合 pattern 字符串的之前的位置, 这是一个非获取匹配.
: Windows (?=95|98|NT|2000) 匹配 Windows 2000 中的 Windows, 而不匹配 Windows 3.1 中的 Windows.
最终返回的是 Windows 而不包含 pattern 匹配的 2000 部分.

(?<=pattern)

肯定反查(Positive Lookbehind). 作用类似 ^, 匹配任何前缀有符合 pattern 的字符串之后的位置, 这是一个非获取匹配.
: (?<=Windows|MacOS|Linux|Unix) Now 匹配 Windows Now 中的 Now, 而不匹配 PalmOS Now 中的 Now.
最终返回的是 Now 而不包含 pattern 匹配的 Windows 部分.

(?!pattern)

否定正查(Negative Lookahead). 作用类似否定的 $, 匹配任何后缀不符合 pattern 字符串的之前的位置, 这是一个非获取匹配.
: Windows(?!95|98|NT|2000) 匹配 Windows 3.1 中的 Windows, 但不匹配 Windows 2000 中的 Windows.
最终返回的是 Windows 而不包含 pattern 匹配的 3.1 部分.

(?<!pattern)

否定反查(Negative Lookbehind). 作用类似否定的 ^, 匹配任何前缀不符合 pattern 的字符串之后的位置, 这是一个非获取匹配.
: (?<!Windows|MacOS|Linux|Unix) Now 匹配 PalmOS Now 中的 Now, 而不匹配 Windows Now 中的 Now.
最终返回的是 Now 而不包含 pattern 匹配的 PalmOS 部分.

 

转义字符表

范例

说明

\w

表示任意字母和数字, 等价于 [a-zA-Z0-9]

\W

表示任意非字母和数字字符, 等价于[^a-zA-Z0-9]

\s

表示任何空白字符, 包括空格, 制表符, 换页符等等, 等价于 [ \f\n\r\t\v]

\S

表示任何非空白字符, 等价于 [^ \f\n\r\t\v]

\d

表示任意数字, 等价于 [0-9]

\D

表示任意非数字字符, 等价于 [^0-9]

\b

表示单词边界, 即字母和空格之间的位置. 也可能表示退格键.

\B

表示非单词边界

\1 - \10

表示前面用 () 包含的第 n 个子表达式.
: <t(.*?)>caption<\/\1> 可以匹配 <title>caption</title>, 注意里面的 \1 .

\t

表示制表符

\n

表示换行符

\r

表示回车符

\x##

表示十六进制值为 ## 的字符, ## 必须为两个字符. 正则表达式中使用 ASCII 编码.
: \x41 等价于 A , \x041 则等价于 \x04 后面带一个字符 1 .

\u####

表示十六进制值为 #### Unicode 字符.
: \u00A9 等价于版权符号 © .

 



Tags: 正则表达式

正则表达式收藏

匹配中文字符的正则表达式: [\u4e00-\u9fa5]

匹配双字节字符(包括汉字在内):[^\x00-\xff]

匹配空行的正则表达式:\n[\s| ]*\r

匹配HTML标记的正则表达式:/<(.*)>.*<\/\1>|<(.*) \/>/

匹配首尾空格的正则表达式:(^\s*)|(\s*$)

匹配Email地址的正则表达式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*

匹配Email地址的正则表达式:^((?>[a-zA-Z\d!#$%&'*+\-/=?^_`{|}~]+\x20*|"((?=[\x01-\x7f])[^"\\]|\\[\x01-\x7f])*"\x20*)*(?<angle><))?((?!\.)(?>\.?[a-zA-Z\d!#$%&'*+\-/=?^_`{|}~]+)+|"((?=[\x01-\x7f])[^"\\]|\\[\x01-\x7f])*")@(((?!-)[a-zA-Z\d\-]+(?<!-)\.)+[a-zA-Z]{2,}|\[(((?(?<!\[)\.)(25[0-5]|2[0-4]\d|[01]?\d?\d)){4}|[a-zA-Z\d\-]*[a-zA-Z\d]:((?=[\x01-\x7f])[^\\\[\]]|\\[\x01-\x7f])+)\])(?(angle)>)$
(放在验证控件里面会有问题,用Regex类使用没有问题。有人知道原因么```知道的请告诉我。)

匹配网址URL的正则表达式:http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?

匹配网址URL的正则表达式:(((ht|f)tp(s?):\/\/)|(www\.[^ \[\]\(\)\n\r\t]+)|(([012]?[0-9]{1,2}\.){3}[012]?[0-9]{1,2})\/)([^ \[\]\(\),;"'<>\n\r\t]+)([^\. \[\]\(\),;"'<>\n\r\t])|(([012]?[0-9]{1,2}\.){3}[012]?[0-9]{1,2})

匹配非负整数(正整数 + 0): ^\d+$  
匹配正整数: ^[0-9]*[1-9][0-9]*$  
匹配非正整数(负整数 + 0): ^((-\d+)|(0+))$  
匹配负整数: ^-[0-9]*[1-9][0-9]*$  
匹配整数: ^-?\d+$    
匹配非负浮点数(正浮点数 + 0): ^\d+(\.\d+)?$  
匹配正浮点数: ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$  
匹配非正浮点数(负浮点数 + 0): ^((-\d+(\.\d+)?)|(0+(\.0+)?))$  
匹配负浮点数 : ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$  
匹配浮点数: ^(-?\d+)(\.\d+)?$  
匹配由26个英文字母组成的字符串: ^[A-Za-z]+$  
匹配由26个英文字母的大写组成的字符串 : ^[A-Z]+$  
匹配由26个英文字母的小写组成的字符串: ^[a-z]+$  
匹配由数字和26个英文字母组成的字符串: ^[A-Za-z0-9]+$  
匹配由数字、26个英文字母或者下划线组成的字符串: ^\w+$  
匹配url : ^[a-zA-z]+://匹配(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\S*)?$  

英语域名的正则表达式:^[a-zA-Z0-9\-]+\.(com|net|org|co.uk|org.uk|ltd.uk|plc.uk|me.uk|edu|mil|br.com|cn.com|eu.com|hu.com|no.com|qc.com|sa.com|se.com|se.net|us.com|uy.com|za.com|ac|co.ac|gv.ac|or.ac|ac.ac|af|am|as|at|ac.at|co.at|gv.at|or.at|asn.au|com.au|edu.au|org.au|net.au|be|ac.be|br|adm.br|adv.br|am.br|arq.br|art.br|bio.br|cng.br|cnt.br|com.br|ecn.br|eng.br|esp.br|etc.br|eti.br|fm.br|fot.br|fst.br|g12.br|gov.br|ind.br|inf.br|jor.br|lel.br|med.br|mil.br|net.br|nom.br|ntr.br|odo.br|org.br|ppg.br|pro.br|psc.br|psi.br|rec.br|slg.br|tmp.br|tur.br|tv.br|vet.br|zlg.br|ca|ab.ca|bc.ca|mb.ca|nb.ca|nf.ca|ns.ca|nt.ca|on.ca|pe.ca|qc.ca|sk.ca|yk.ca|cc|ac.cn|com.cn|edu.cn|gov.cn|net.cn|org.cn|cn|bj.cn|sh.cn|tj.cn|cq.cn|he.cn|nm.cn|ln.cn|jl.cn|hl.cn|js.cn|zj.cn|ah.cn|hb.cn|hn.cn|gd.cn|gx.cn|hi.cn|sc.cn|gz.cn|yn.cn|xz.cn|sn.cn|gs.cn|qh.cn|nx.cn|xj.cn|tw.cn|hk.cn|mo.cn|cx|cz|de|dk|fo|com.ec|org.ec|net.ec|mil.ec|fin.ec|med.ec|gov.ec|fr|tm.fr|com.fr|asso.fr|presse.fr|gf|gs|co.il|org.il|net.il|ac.il|k12.il|gov.il|muni.il|ac.in|co.in|ernet.in|gov.in|net.in|res.in|is|it|ac.jp|co.jp|go.jp|or.jp|ne.jp|ac.kr|co.kr|go.kr|ne.kr|nm.kr|or.kr|re.kr|li|lt|lu|asso.mc|tm.mc|com.mm|org.mm|net.mm|edu.mm|gov.mm|ms|mx|com.mx|org.mx|net.mx|edu.mx|gov.mx|gob.mx|nl|no|nu|pl|com.pl|net.pl|org.pl|aid.pl|agro.pl|atm.pl|auto.pl|biz.pl|edu.pl|gmina.pl|gsm.pl|info.pl|mail.pl|miasta.pl|media.pl|mil.pl|nom.pl|pc.pl|priv.pl|realestate.pl|rel.pl|shop.pl|sklep.pl|sos.pl|targi.pl|tm.pl|tourism.pl|travel.pl|turystyka.pl|pt|com.ro|org.ro|store.ro|tm.ro|firm.ro|www.ro|arts.ro|rec.ro|info.ro|nom.ro|nt.ro|ru|com.ru|net.ru|org.ru|se|si|com.sg|org.sg|net.sg|gov.sg|sk|st|tc|tf|ac.th|co.th|go.th|mi.th|net.th|or.th|tj|tm|to|bbs.tr|com.tr|edu.tr|gov.tr|k12.tr|mil.tr|net.tr|org.tr|com.tw|org.tw|net.tw|ac.uk|uk.co|uk.com|uk.net|gb.com|gb.net|vg|ac.za|alt.za|co.za|edu.za|gov.za|mil.za|net.za|ngo.za|nom.za|org.za|school.za|tm.za|web.za|sh|kz|ch|info|ua|biz|ws|gov|tv|name|pro|ie|com.hk|org.hk|net.hk|edu.hk|us|tk|cd|aero|gr|by|ad|lv|eu.lv|bz|es|jp|cl|ag|uni.cc|COM|NET|ORG|CO.UK|ORG.UK|LTD.UK|PLC.UK|ME.UK|EDU|MIL|BR.COM|CN.COM|EU.COM|HU.COM|NO.COM|QC.COM|SA.COM|SE.COM|SE.NET|US.COM|UY.COM|ZA.COM|AC|CO.AC|GV.AC|OR.AC|AC.AC|AF|AM|AS|AT|AC.AT|CO.AT|GV.AT|OR.AT|ASN.AU|COM.AU|EDU.AU|ORG.AU|NET.AU|BE|AC.BE|BR|ADM.BR|ADV.BR|AM.BR|ARQ.BR|ART.BR|BIO.BR|CNG.BR|CNT.BR|COM.BR|ECN.BR|ENG.BR|ESP.BR|ETC.BR|ETI.BR|FM.BR|FOT.BR|FST.BR|G12.BR|GOV.BR|IND.BR|INF.BR|JOR.BR|LEL.BR|MED.BR|MIL.BR|NET.BR|NOM.BR|NTR.BR|ODO.BR|ORG.BR|PPG.BR|PRO.BR|PSC.BR|PSI.BR|REC.BR|SLG.BR|TMP.BR|TUR.BR|TV.BR|VET.BR|ZLG.BR|CA|AB.CA|BC.CA|MB.CA|NB.CA|NF.CA|NS.CA|NT.CA|ON.CA|PE.CA|QC.CA|SK.CA|YK.CA|CC|AC.CN|COM.CN|EDU.CN|GOV.CN|NET.CN|ORG.CN|CN|BJ.CN|SH.CN|TJ.CN|CQ.CN|HE.CN|NM.CN|LN.CN|JL.CN|HL.CN|JS.CN|ZJ.CN|AH.CN|HB.CN|HN.CN|GD.CN|GX.CN|HI.CN|SC.CN|GZ.CN|YN.CN|XZ.CN|SN.CN|GS.CN|QH.CN|NX.CN|XJ.CN|TW.CN|HK.CN|MO.CN|CX|CZ|DE|DK|FO|COM.EC|ORG.EC|NET.EC|MIL.EC|FIN.EC|MED.EC|GOV.EC|FR|TM.FR|COM.FR|ASSO.FR|PRESSE.FR|GF|GS|CO.IL|ORG.IL|NET.IL|AC.IL|K12.IL|GOV.IL|MUNI.IL|AC.IN|CO.IN|ERNET.IN|GOV.IN|NET.IN|RES.IN|IS|IT|AC.JP|CO.JP|GO.JP|OR.JP|NE.JP|AC.KR|CO.KR|GO.KR|NE.KR|NM.KR|OR.KR|RE.KR|LI|LT|LU|ASSO.MC|TM.MC|COM.MM|ORG.MM|NET.MM|EDU.MM|GOV.MM|MS|MX|COM.MX|ORG.MX|NET.MX|EDU.MX|GOV.MX|GOB.MX|NL|NO|NU|PL|COM.PL|NET.PL|ORG.PL|AID.PL|AGRO.PL|ATM.PL|AUTO.PL|BIZ.PL|EDU.PL|GMINA.PL|GSM.PL|INFO.PL|MAIL.PL|MIASTA.PL|MEDIA.PL|MIL.PL|NOM.PL|PC.PL|PRIV.PL|REALESTATE.PL|REL.PL|SHOP.PL|SKLEP.PL|SOS.PL|TARGI.PL|TM.PL|TOURISM.PL|TRAVEL.PL|TURYSTYKA.PL|PT|COM.RO|ORG.RO|STORE.RO|TM.RO|FIRM.RO|WWW.RO|ARTS.RO|REC.RO|INFO.RO|NOM.RO|NT.RO|RU|COM.RU|NET.RU|ORG.RU|SE|SI|COM.SG|ORG.SG|NET.SG|GOV.SG|SK|ST|TC|TF|AC.TH|CO.TH|GO.TH|MI.TH|NET.TH|OR.TH|TJ|TM|TO|BBS.TR|COM.TR|EDU.TR|GOV.TR|K12.TR|MIL.TR|NET.TR|ORG.TR|COM.TW|ORG.TW|NET.TW|AC.UK|UK.CO|UK.COM|UK.NET|GB.COM|GB.NET|VG|AC.ZA|ALT.ZA|CO.ZA|EDU.ZA|GOV.ZA|MIL.ZA|NET.ZA|NGO.ZA|NOM.ZA|ORG.ZA|SCHOOL.ZA|TM.ZA|WEB.ZA|SH|KZ|CH|INFO|UA|BIZ|WS|GOV|TV|NAME|PRO|IE|COM.HK|ORG.HK|NET.HK|EDU.HK|US|TK|CD|AERO|GR|BY|AD|LV|EU.LV|BZ|ES|JP|CL|AG|UNI.CC)$

中文域名的正则表达式:^[\u4e00-\u9fa5]+\.(com|net|org|co.uk|org.uk|ltd.uk|plc.uk|me.uk|edu|mil|br.com|cn.com|eu.com|hu.com|no.com|qc.com|sa.com|se.com|se.net|us.com|uy.com|za.com|ac|co.ac|gv.ac|or.ac|ac.ac|af|am|as|at|ac.at|co.at|gv.at|or.at|asn.au|com.au|edu.au|org.au|net.au|be|ac.be|br|adm.br|adv.br|am.br|arq.br|art.br|bio.br|cng.br|cnt.br|com.br|ecn.br|eng.br|esp.br|etc.br|eti.br|fm.br|fot.br|fst.br|g12.br|gov.br|ind.br|inf.br|jor.br|lel.br|med.br|mil.br|net.br|nom.br|ntr.br|odo.br|org.br|ppg.br|pro.br|psc.br|psi.br|rec.br|slg.br|tmp.br|tur.br|tv.br|vet.br|zlg.br|ca|ab.ca|bc.ca|mb.ca|nb.ca|nf.ca|ns.ca|nt.ca|on.ca|pe.ca|qc.ca|sk.ca|yk.ca|cc|ac.cn|com.cn|edu.cn|gov.cn|net.cn|org.cn|cn|bj.cn|sh.cn|tj.cn|cq.cn|he.cn|nm.cn|ln.cn|jl.cn|hl.cn|js.cn|zj.cn|ah.cn|hb.cn|hn.cn|gd.cn|gx.cn|hi.cn|sc.cn|gz.cn|yn.cn|xz.cn|sn.cn|gs.cn|qh.cn|nx.cn|xj.cn|tw.cn|hk.cn|mo.cn|cx|cz|de|dk|fo|com.ec|org.ec|net.ec|mil.ec|fin.ec|med.ec|gov.ec|fr|tm.fr|com.fr|asso.fr|presse.fr|gf|gs|co.il|org.il|net.il|ac.il|k12.il|gov.il|muni.il|ac.in|co.in|ernet.in|gov.in|net.in|res.in|is|it|ac.jp|co.jp|go.jp|or.jp|ne.jp|ac.kr|co.kr|go.kr|ne.kr|nm.kr|or.kr|re.kr|li|lt|lu|asso.mc|tm.mc|com.mm|org.mm|net.mm|edu.mm|gov.mm|ms|mx|com.mx|org.mx|net.mx|edu.mx|gov.mx|gob.mx|nl|no|nu|pl|com.pl|net.pl|org.pl|aid.pl|agro.pl|atm.pl|auto.pl|biz.pl|edu.pl|gmina.pl|gsm.pl|info.pl|mail.pl|miasta.pl|media.pl|mil.pl|nom.pl|pc.pl|priv.pl|realestate.pl|rel.pl|shop.pl|sklep.pl|sos.pl|targi.pl|tm.pl|tourism.pl|travel.pl|turystyka.pl|pt|com.ro|org.ro|store.ro|tm.ro|firm.ro|www.ro|arts.ro|rec.ro|info.ro|nom.ro|nt.ro|ru|com.ru|net.ru|org.ru|se|si|com.sg|org.sg|net.sg|gov.sg|sk|st|tc|tf|ac.th|co.th|go.th|mi.th|net.th|or.th|tj|tm|to|bbs.tr|com.tr|edu.tr|gov.tr|k12.tr|mil.tr|net.tr|org.tr|com.tw|org.tw|net.tw|ac.uk|uk.co|uk.com|uk.net|gb.com|gb.net|vg|ac.za|alt.za|co.za|edu.za|gov.za|mil.za|net.za|ngo.za|nom.za|org.za|school.za|tm.za|web.za|sh|kz|ch|info|ua|biz|ws|gov|tv|name|pro|ie|com.hk|org.hk|net.hk|edu.hk|us|tk|cd|aero|gr|by|ad|lv|eu.lv|bz|es|jp|cl|ag|uni.cc|COM|NET|ORG|CO.UK|ORG.UK|LTD.UK|PLC.UK|ME.UK|EDU|MIL|BR.COM|CN.COM|EU.COM|HU.COM|NO.COM|QC.COM|SA.COM|SE.COM|SE.NET|US.COM|UY.COM|ZA.COM|AC|CO.AC|GV.AC|OR.AC|AC.AC|AF|AM|AS|AT|AC.AT|CO.AT|GV.AT|OR.AT|ASN.AU|COM.AU|EDU.AU|ORG.AU|NET.AU|BE|AC.BE|BR|ADM.BR|ADV.BR|AM.BR|ARQ.BR|ART.BR|BIO.BR|CNG.BR|CNT.BR|COM.BR|ECN.BR|ENG.BR|ESP.BR|ETC.BR|ETI.BR|FM.BR|FOT.BR|FST.BR|G12.BR|GOV.BR|IND.BR|INF.BR|JOR.BR|LEL.BR|MED.BR|MIL.BR|NET.BR|NOM.BR|NTR.BR|ODO.BR|ORG.BR|PPG.BR|PRO.BR|PSC.BR|PSI.BR|REC.BR|SLG.BR|TMP.BR|TUR.BR|TV.BR|VET.BR|ZLG.BR|CA|AB.CA|BC.CA|MB.CA|NB.CA|NF.CA|NS.CA|NT.CA|ON.CA|PE.CA|QC.CA|SK.CA|YK.CA|CC|AC.CN|COM.CN|EDU.CN|GOV.CN|NET.CN|ORG.CN|CN|BJ.CN|SH.CN|TJ.CN|CQ.CN|HE.CN|NM.CN|LN.CN|JL.CN|HL.CN|JS.CN|ZJ.CN|AH.CN|HB.CN|HN.CN|GD.CN|GX.CN|HI.CN|SC.CN|GZ.CN|YN.CN|XZ.CN|SN.CN|GS.CN|QH.CN|NX.CN|XJ.CN|TW.CN|HK.CN|MO.CN|CX|CZ|DE|DK|FO|COM.EC|ORG.EC|NET.EC|MIL.EC|FIN.EC|MED.EC|GOV.EC|FR|TM.FR|COM.FR|ASSO.FR|PRESSE.FR|GF|GS|CO.IL|ORG.IL|NET.IL|AC.IL|K12.IL|GOV.IL|MUNI.IL|AC.IN|CO.IN|ERNET.IN|GOV.IN|NET.IN|RES.IN|IS|IT|AC.JP|CO.JP|GO.JP|OR.JP|NE.JP|AC.KR|CO.KR|GO.KR|NE.KR|NM.KR|OR.KR|RE.KR|LI|LT|LU|ASSO.MC|TM.MC|COM.MM|ORG.MM|NET.MM|EDU.MM|GOV.MM|MS|MX|COM.MX|ORG.MX|NET.MX|EDU.MX|GOV.MX|GOB.MX|NL|NO|NU|PL|COM.PL|NET.PL|ORG.PL|AID.PL|AGRO.PL|ATM.PL|AUTO.PL|BIZ.PL|EDU.PL|GMINA.PL|GSM.PL|INFO.PL|MAIL.PL|MIASTA.PL|MEDIA.PL|MIL.PL|NOM.PL|PC.PL|PRIV.PL|REALESTATE.PL|REL.PL|SHOP.PL|SKLEP.PL|SOS.PL|TARGI.PL|TM.PL|TOURISM.PL|TRAVEL.PL|TURYSTYKA.PL|PT|COM.RO|ORG.RO|STORE.RO|TM.RO|FIRM.RO|WWW.RO|ARTS.RO|REC.RO|INFO.RO|NOM.RO|NT.RO|RU|COM.RU|NET.RU|ORG.RU|SE|SI|COM.SG|ORG.SG|NET.SG|GOV.SG|SK|ST|TC|TF|AC.TH|CO.TH|GO.TH|MI.TH|NET.TH|OR.TH|TJ|TM|TO|BBS.TR|COM.TR|EDU.TR|GOV.TR|K12.TR|MIL.TR|NET.TR|ORG.TR|COM.TW|ORG.TW|NET.TW|AC.UK|UK.CO|UK.COM|UK.NET|GB.COM|GB.NET|VG|AC.ZA|ALT.ZA|CO.ZA|EDU.ZA|GOV.ZA|MIL.ZA|NET.ZA|NGO.ZA|NOM.ZA|ORG.ZA|SCHOOL.ZA|TM.ZA|WEB.ZA|SH|KZ|CH|INFO|UA|BIZ|WS|GOV|TV|NAME|PRO|IE|COM.HK|ORG.HK|NET.HK|EDU.HK|US|TK|CD|AERO|GR|BY|AD|LV|EU.LV|BZ|ES|JP|CL|AG|UNI.CC)$

匹配日期的完美正则(一般用于判断单个的日期验证):
^(?:(?:1[6-9]|[2-9]\d)?\d{2}[\/\-\.](?:0?[1,3-9]|1[0-2])[\/\-\.](?:29|30))(?: (?:0?\d|1\d|2[0-3])\:(?:0?\d|[1-5]\d)\:(?:0?\d|[1-5]\d)(?: \d{1,3})?)?$|^(?:(?:1[6-9]|[2-9]\d)?\d{2}[\/\-\.](?:0?[1,3,5,7,8]|1[02])[\/\-\.]31)(?: (?:0?\d|1\d|2[0-3])\:(?:0?\d|[1-5]\d)\:(?:0?\d|[1-5]\d)(?: \d{1,3})?)?$|^(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])[\/\-\.]0?2[\/\-\.]29)(?: (?:0?\d|1\d|2[0-3])\:(?:0?\d|[1-5]\d)\:(?:0?\d|[1-5]\d)(?: \d{1,3})?)?$|^(?:(?:16|[2468][048]|[3579][26])00[\/\-\.]0?2[\/\-\.]29)(?: (?:0?\d|1\d|2[0-3])\:(?:0?\d|[1-5]\d)\:(?:0?\d|[1-5]\d)(?: \d{1,3})?)?$|^(?:(?:1[6-9]|[2-9]\d)?\d{2}[\/\-\.](?:0?[1-9]|1[0-2])[\/\-\.](?:0?[1-9]|1\d|2[0-8]))(?: (?:0?\d|1\d|2[0-3])\:(?:0?\d|[1-5]\d)\:(?:0?\d|[1-5]\d)(?: \d{1,3})?)?$


匹配日期验证:(一般用于在大量字符串中查询日期 格式:年[四位](任意字符)月[两位](任意字符)日[两位]   解决闰年的日期问题)
((((19|20)(([02468][048])|([13579][26]))\D{1}02\D?29))|((20[0-9][0-9])|(19[0-9][0-9]))\D{1}((((0[1-9])|(1[0-2]))\D{1}((0[1-9])|(1\d)|(2[0-8])))|((((0[13578])|(1[02]))\D{1}31)|(((01,3-9])|(1[0-2]))\D{1}(29|30)))))

匹配日期验证:(一般用于在大量字符串中查询日期 格式:年[四位](任意字符)月[一位-两位](任意字符)日[一位-两位]  )
(\d{4})\D{1}(0{0,1}[1-9]|1[0-2])\D{1}([12]\d|0{0,1}[1-9]|3[01])  如果要加上可选时间 接着后面加 (\D{1}([01]\d|2[0-3])\D{1}([0-5]\d)\D{1}([0-5]\d)?)?

匹配日期验证:(一般用于在大量字符串中查询日期 格式:月(任意字符)[一位或者多位]/日(任意字符)[一位或者多位]/年[四位]
([0]?\d|[1][0-2]).+([0-2]?\d|[3][0-1]).+([2][0-9]|[1][6-9])\d{2}
PS:这个用于查找 whois 这样BT的日期形式 比如baidu的 expires on..............: sat, oct 11, 2014  这样的日期先把oct转成数字以后用此正则可以找出来。

扩展一下:([0-2]?\d|[3][0-1]).+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec|jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec).+([2][0-9]|[1][6-9])\d{2} 
                        这样适合   Record expires on 04-May-2011.
                                  Record created on 03-May-1996.
                                  Database last updated on 15-Aug-2006 04:09:00 EDT.


上述日期还需要加上时间 在后面加段  “空格 (20|21|22|23|[0-1]?\d):[0-5]?\d:[0-5]?\d ”即可。


利用正则表达式限制网页表单里的文本框输入内容:

用正则表达式限制只能输入中文:onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\u4E00-\u9FA5]/g,''))"

用正则表达式限制只能输入全角字符: onkeyup="value=value.replace(/[^\uFF00-\uFFFF]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\uFF00-\uFFFF]/g,''))"

用正则表达式限制只能输入数字:onkeyup="value=value.replace(/[^\d]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"

用正则表达式限制只能输入数字和英文:onkeyup="value=value.replace(/[\W]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"

 1function regInput(obj, reg, inputStr)
 2{   
 3    // 从当前文本选中区中创建 TextRange 对象,或从控件选中区中创建 controlRange 集合。
 4    var docSel    = document.selection.createRange();
 5    // 如果父控件不是input就返回
 6    if (docSel.parentElement().tagName != "INPUT")    
 7        return false;
 8    // 返回 TextRange 的副本。
 9    oSel = docSel.duplicate();
10    oSel.text = "";
11    // 创建一个 obj 的 TextRange 对象
12    var srcRange = obj.createTextRange();
13    // 设置一个范围终点根据其它范围终点。
14    oSel.setEndPoint("StartToStart", srcRange)
15    var str = oSel.text + inputStr + srcRange.text.substr(oSel.text.length)
16    // 返回一个 Boolean 值,它指出在被查找的字符串中是否存在。
17    return reg.test(str)
18}

19
20function regInput(obj, reg, inputStr, inputCode)
21{
22    // 判断如果是功能键就返回真
23    // 8 back 9 tab 16 shift 17 ctrl 45 insert 46 del 35 end 36 home 37 ← 38 ↑ 39 → 40 ↓
24    if(inputCode == 8 || inputCode == 9 || inputCode == 16 || inputCode == 17 || inputCode == 46 || inputCode == 45 || inputCode == 35 || inputCode == 36 || inputCode == 37 || inputCode == 38 || inputCode == 39 || inputCode == 40)
25    {
26        return true;
27    }

28    // 从当前文本选中区中创建 TextRange 对象,或从控件选中区中创建 controlRange 集合。
29    var docSel    = document.selection.createRange();
30    // 如果父控件不是input就返回
31    if (docSel.parentElement().tagName != "INPUT")    
32        return false;
33    // 返回 TextRange 的副本。
34    oSel = docSel.duplicate();
35    oSel.text = "";
36    // 创建一个 obj 的 TextRange 对象
37    var srcRange = obj.createTextRange();
38    // 设置一个范围终点根据其它范围终点。
39    oSel.setEndPoint("StartToStart", srcRange)
40    var str = oSel.text + inputStr + srcRange.text.substr(oSel.text.length)
41    // 返回一个 Boolean 值,它指出在被查找的字符串中是否存在。
42    return reg.test(str)
43}

44
45function assignKeys()
46{
47    var keyboard = document.getElementById("divSignIn");
48    var inputKeys = keyboard.getElementsByTagName("input");    
49    if(inputKeys)
50    {
51        var length = inputKeys.length;
52         
53        for(var i=0;i<length;i++)
54        {
55            var key = inputKeys[i];
56            key.onkeydown = function(){return regInput(this,/^\w*$/,String.fromCharCode(event.keyCode),event.keyCode)};
57            key.onpaste = function(){return regInput(this,/^\w*$/,window.clipboardData.getData('Text'))};
58            key.ondrop = function(){return regInput(this,/^\w*$/,event.dataTransfer.getData('Text'))};
59        }

60    }
            
61