您当前的位置: 首页 >  正则表达式

正则表达式经典教程

发布时间:2004-10-27 19:09:00 ,浏览量:0

作者:ET Dreams http://blog.csdn.net/etmonitor/ Regular Expressions (1) ---- What is Regular Expressions?

 

正则表达式是常见常忘,所以还是记下来比较保险,于是就有了这篇笔记。

希望对大家会有所帮助。J

1.什么是正则表达式.............................................................................................................................................................. 2

2.正则表达式的起源............................................................................................................................................................. 2

3. 正则表达式使用祥解........................................................................................................................................................ 3

3.1基本语法.............................................................................................................................................................................. 3

3.1.1普通字符..................................................................................................................................................................... 3

3.1.2非打印字符................................................................................................................................................................. 3

3.1.3特殊字符..................................................................................................................................................................... 3

3.1.4字符集........................................................................................................................................................................... 4

3.1.5在字符集中使用元字符............................................................................................................................................. 5

3.1.6预定义字符集.............................................................................................................................................................. 5

3.1.7 限定符........................................................................................................................................................................... 6

3.1.8定位符........................................................................................................................................................................... 6

3.1.9 “.”元字符...................................................................................................................................................................... 7

3.1.10用 “|”表示选择.......................................................................................................................................................... 8

3.1.11用 “()”表示分组.................................................................................................................................................. 8

3.1.12 “?”的补充说明.......................................................................................................................................................... 8

3.1.13给正则表达式添加注释......................................................................................................................................... 8

3.1.14操作符的运算优先级............................................................................................................................................... 8

3.2 高级话题............................................................................................................................................................................... 9

3.2.1反向引用..................................................................................................................................................................... 9

3.2.2在正则表达式中指定模式option........................................................................................................................... 9

3.2.3 Lookaround断言..................................................................................................................................................... 10

4. 正则表达式基本语法索引............................................................................................................................................ 11

5.   正则表达式高级语法索引.............................................................................................................................................. 15

6.   参考资料................................................................................................................................................................................. 17

7.   推荐工具................................................................................................................................................................................. 17

 

 

 

 

 

 

 

 

 

 

 

 

 

1.什么是正则表达式

 

简单的说,正则表达式是一种可以用于文字模式匹配和替换的强有力的工具。是由一系列普通字符和特殊字符组成的能明确描述文本字符串的文字匹配模式。

正则表达式并非一门专用语言,但也可以看作是一种语言,它可以让用户通过使用一系列普通字符和特殊字符构建能明确描述文本字符串的匹配模式。除了简单描述这些模式之外,正则表达式解释引擎通常可用于遍历匹配,并使用模式作为分隔符来将字符串解析为子字符串,或以智能方式替换文本或重新设置文本格式。正则表达式为解决与文本处理有关的许多常见任务提供了有效而简捷的方式。

正则表达式具有两种标准:

·         基本的正则表达式(BRE – Basic Regular Expressions)

·         扩展的正则表达式(ERE – Extended Regular Expressions)。

ERE包括BRE功能和另外其它的概念。

 

正则表达式目前有两种解释引擎:

·         基于字符驱动(text-directed engine)

·         基于正则表达式驱动(regex-directed engine)

Jeffery Friedl把它们称作DFA和NFA解释引擎。

 

约定:

为了描述起来方便,在本文中做一些约定:

1.      本文所举例的所有表达时都是基于NFA解释引擎的。

2.      正则表达式,也就是匹配模式,会简写为Regex。

3.      Regex的匹配目标,也就是目标字符串,会简写为String。

4.      匹配结果用会用黄色底色标识。

5.      用1/+1=2 括起来的表示这是一个regex。

6.      举例会用以下格式:

Regex

Target String

Description

test

This is a test

会匹配test,testcase等

 

2.正则表达式的起源

正则表达式的“祖先”可以一直上溯至对人类神经系统如何工作的早期研究。Warren McCulloch 和 Walter Pitts 这两位神经生理学家研究出一种数学方式来描述这些神经网络。

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

随后,发现可以将这一工作应用于使用Ken Thompson 的计算搜索算法的一些早期研究,Ken Thompson是Unix 的主要发明人。正则表达式的第一个实用应用程序就是 Unix 中的qed 编辑器。从那时起直至现在正则表达式都是基于文本的编辑器和搜索工具中的一个重要部分。具有完整语法的正则表达式使用在字符的格式匹配方面上,后来被应用到熔融信息技术领域。自从那时起,正则表达式经过几个时期的发展,现在的标准已经被ISO(国际标准组织)批准和被Open Group组织认定。

3. 正则表达式使用祥解

最简单的正则表达式相信大家都已熟悉并且经常使用,那就是文字字符串。特定的字符串可通过文字本身加以描述;像 test这样的Regex模式可精确匹配输入的字符串”test”,但是它也可以匹配this is a testcase,这就不是我们想要得结果。

当然,使用正则表达式匹配等于它自身的精确字符串是没有价值的实现,不能体现正则表达式的真正作用。但是,假如要查找的不是test,而是所有以字母 t 开头的单词,或所有4个字母的单词,那该怎么办?这超出了文字字符串的合理范围。所以我们才需要深入地研究正则表达式。

3.1基本语法

虽然正则表达式并非一门专用语言,但它也有一些特殊的规定,也可以称之为基本语法。

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

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

可以通过在一对分隔符之间放入表达式模式的各种组件来构造一个正则表达式。

3.1.1普通字符

由所有那些未显式指定为元字符的打印和非打印字符组成。这包括所有的大写和小写字母字符,所有数字,所有标点符号以及一些符号。

3.1.2非打印字符

非打印字符也是普通字符,单独列出来便于参考。

Symbol

Description

/cx

匹配由x指明的控制字符。例如, /cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。

/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。

 

Regex中可以使用非打印字符。/t会匹配一个tab字符(ASC||),/r 会匹配一个回车(0x0D),/n 会匹配一个换行符(0x0A)。应该注意的是:Windows使用/r/n表示一行的结束,而UNIX使用/n 。

同样,我们可以在Regex中使用16进制的ASCⅡ码或者ANSI标准码。在拉丁语中,版权符号的代码是0xA9,所以我们也可以这样来匹配版权符号 /xA9 。另外一个匹配tab的写法是:/x09 。但是注意,第一位的“0”必须去掉。

 

3.1.3特殊字符

特殊字符也叫做元字符,保留字符(Metacharactor),在Regex中表示特殊的意义,大部分的意思在不同的上下文中的意义是不同的,这里只列出最普遍的意义。

特殊字符共有11个:

Symbol

Description

$

匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '/n' 或 '/r'。要匹配 $ 字符本身,请使用 /$。

( )

标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 /( 和 /)。

*

匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 /*。

+

匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 /+。

.

匹配除换行符 /n之外的任何单字符。要匹配 .,请使用 /。

[

标记一个中括号表达式的开始。要匹配 [,请使用 /[。

?

匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 /?。

/

将下一个字符标记为或特殊字符、或原义字符、或反向引用、或八进制转义符。例如, 'n' 匹配字符 'n'。'/n' 匹配换行符。序列 '//' 匹配 "/",而 '/(' 则匹配 "("。

^

匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符本身,请使用 /^。

{

标记限定符表达式的开始。要匹配 {,请使用 /{。

|

指明两项之间的一个选择。要匹配 |,请使用 /|。

 

在元字符前加 / 转义符,可以把特殊字符当作普通字符来使用。

比如:如要要匹配 1+1=2 ,正确的正则表达式应该为1/+1=2。否则, + 会被当作特殊字符对待。

除了特殊字符,所有的其他字符都不应该加 / 。因为 / 也是一个特殊字符。/ 和普通字符组合在一起也可以创造一种特殊的意义。比如 /d 表示匹配所有的数字。

作为程序员,单引号和双引号不是特殊字符会也许让我们感到很惊讶。但这是正确的。因为我们在编程的时候,编程语言会知道引号之间的哪些字符表示特殊意义,编译器在把字符串x传递给regex解释引擎之前,会把它们处理成regex。比如,在C#中,如果我们要匹配  1/+1=2 ,在程序中我们要这样写: “1//+1=2” ,C#编译器会把 “//” ,处理为一个“/”  。同样,如果要匹配 C:/Temp ,首先,正则表达式要这样写 C://Temp,然后在程序中我们应该这样写:“ C:temp”。

3.1.4字符集

            字符集描述了一组字符,Regex解释器会认为匹配字符集中的一个字符就可以认为匹配成功。

字符集用[ ]括起来即可。

            比如gr[ae]y就可以匹配gray或者grey。

            字符集只能匹配一个字符,gr[ae]y就不能和graey匹配。字符集中的字符顺序是任意的,得到的结果都是唯一的。

            可以在字符集中用连字符“-”来表示一个范围。[0-9]的结果和[0123456789]的匹配结果都是相同的。字符集中的范围可以有多种。比如[0-9a-fA-F]表示匹配所有的16进制,包括大小写。也可以把范围和单个字符组合在一起用,[0-9a-fxA-FX]表示匹配所有的16进制或者一个字符X。字符集的顺序不会影响结果。

            在字符集的开始标志“[”后面加上一个“^”符号,表示否定,表示匹配除字符集中定义的字符以外的所有字符。包括非打印字符和行结束符。

            注意:字符集匹配的一个字符,而不是一个位置。所以。q[^u]的意义不是“q后面的字符不是u”。而是“q后面的字符可以是除了u以外的所有字符”。

            q[^u]不会和Iraq匹配。

但是会和Iraq is a country匹配,因为q后面的空格字符是一个“不是u的字符”。

3.1.5在字符集中使用元字符

字符集中的元字符只能是 ‘]’, ‘/’, ‘^’, 和 ‘-‘ 。

其他元字符在字符集中都失去了特殊意义,表示的只是一个普通字符。也不需要用加“/”。

比如:

匹配一个“*”或者“+”,用[*+]就足够了。即使给他们加上“/”,regex解释器也会把他们忽略掉。

 

四种特殊字符的处理:

在字符集中要表示“]”,“^”和“-”需要在后面加上转义符“/”,来表示它们代表的分别是普通字符“]”,“^”和“-”。

也可以把它们放在一个不能表示特殊意义的位置,后一个方法比较好,因为他们不会影响可读性。

  • “^”

要想匹配一个“^”,可以把它放在除了紧跟“[”的任意一个位置。

Regex

String

Description

[x^]

A string with x and ^.

匹配x或者“^”

 

  •  “]”

可以把“]”放在紧跟着“[”的位置,或者使用否定字符集。

Regex

String

Description

[]x]

A string with x and ]

匹配x或者“]”

[^]x]

A string with x and ]

匹配除了x和”] ”以外的所有字符

  •  “/”

要想把“/”当作一个普通字符来匹配,而不是一个特殊字符,必须把“/”再用一个“/”括起来。

Regex

String

Description

[//x]

A string with x and /

匹配x或者“/”

 

  •  “-”

连字符可以放在紧跟着“[”的后面,或者正好“]”的前面,或者紧跟着“^”的后面。

Regex

String

Description

[-x]

A string with x and -

匹配x或者“-”

[x-]

A string with x and -

匹配x或者“-”

3.1.6预定义字符集

因为很多字符集是经常使用的,所以Regex解释器预定义了一些常用字符集:

Regex

Meaning

Description

/d

[0-9]

所有数字

/w

[a-zA-Z]

表示所有的字符,和文化字体有关

/s

[ /t/r/n]

空格,回车和tab。和文化字体有关

 

预订一字符集可以既可以用在字符集里面,也可以用在字符集外面。

Regex

String

Description

/s/d

1+2=3

匹配后面紧跟着一个数字的空白符

[/s/d]

1+2=3

匹配一个单独的字符或者一个数字或者一个空白符

[/da-fA-F]和[0-9a-fA-F]的匹配结果是一样的。

 

同样,在预定义字符集前面加一个“^”符号表示否定。它们也有预先定义好的表示:

Regex

Meaning

Description

/D

[^/d]

非数字

/W

[^/w]

非字符,和文化字体有关

/S

[^/s]

非空格,回车和tab。和文化字体有关

 

在“[]”使用否定预订一字符集时要特别心。[/D/S]不等于[/^d/s]。[/^d/s]会匹配除了数字和空白符以外的所有字符。而[/D/S]会匹配要么不是一个数字,要么是空白符。因为数字不是空白符,空白符也不是数字,所以[/D/S]会匹配任意的字符。

3.1.7 限定符

限定符提供了一种简单方法,用于指定在模式中允许特定字符或字符集自身重复出现的次数。限定符始终引用限定符前(左边)的模式,通常是单个字符,除非使用括号创建模式组。

限定符有*或+或?或{n}或{n,}或{n,m}共6种。

Symbol

Description

Description

?

0次获1次

 

*

0次或n次

 

+

1次或n次

 

{min, max}

最少min次,最多max次

Max必须大于等于min。

{min,<不指定> }

最少min次,或者n次

 

{min}

精确的重复min次

 

在字符集后面使用 “?”,”*”,”+”,表示重复。会重复整个的字符集,而不是重复匹配的那个字符。

Regex

String

意义

[0-9]+

846,111

匹配数字

([0-9))+

846,111

匹配数字相同的数字

[0-9]+会匹配846,也会匹配111。

如果想要重复的只是匹配的那个字符,而不是整个字符集,则必须使用“反向引用”。

([0-9])/1+ 只会匹配111,而不会匹配846。

(第二部分高级话题会讲道)

如果目标string是 811116。则1111会被匹配。如果不想这样,则需要使用

lookahead和lookbehind。

(第二部分高级话题会讲道)

3.1.8定位符

到现在为止,我们已经熟悉了普通字符、特殊字符(元字符)和字符集。在这两种情况下,Regex匹配的都是一个字符。

定位符是另外一种,它不匹配字符,相反,它匹配的是一个位置。

定位符有几种:

Regex

Function

Description

^

第一个字符之前的位置

包含换行符

$

最后一个字符后面的位置

包含换行符

/A

总是匹配string的第一个位置

不包含换行符

/Z

总是匹配string的最后一个位置

不包含换行符

 

Regex

String

意义

^

Abc

匹配A之前的位置

$

Abc

匹配c后面的位置

^A

Abc

匹配A

^b

Abc

不能匹配

c$

Abc

匹配c

A$

Abc

不能匹配

 

词的边界

还有一种定位符匹配的是一个词(word)的边界。用/b表示。

词(word)是由可以组成词的字符组成(“word characters”),“word characters”就是可以组成词的字符,不包括非打印字符和回车换行。

有四种不同的位置被认为是词的边界:

  1. 第一个字符之前的位置,如果第一个字符是一个“word character”。
  2. 最后一个字符之后的位置,如果最后一个字符是一个“word character”。
  3. 介于词和非词之间的紧跟着词的位置。
  4. 介于非词和词之间的紧跟着非词的位置

所有的word characters都可以用/w来表示。

所有的non-word characters都可以用/W来表示。

 

/b匹配一个词的边界。

/B表示一个非词的边界的位置,它能匹配任意一个不是次的边界的位置。

3.1.9 “.”元字符

在正则表达式中,“.”是用的最多的一个元字符,同时,它也是最容易用错的一个。所以我们单独来讲。

“.”几乎匹配任何字符。唯一的一个例外是换行符。

这个例外存在是有历史原因的。第一个用正则表达式的工具是基于换行符的。它从文件中读取一行字符,然后用去匹配。因为在这些工具中,string中永远不可能有换行符,所以“.”也永远不会和换行符匹配。

现代的工具可以用正则表达式去和很大的一个string甚至整个文件去匹配。所以现在的Regex解释器都含有一个选项,激活以后就可以让“.”去匹配所有的字符,包括换行符。

 “.”是一个非常强大的元字符。它可以让我们偷懒。但是我们要慎重的使用。我们看一个例子:

我们要匹配一个mm/dd/yy的格式的日期。但是我们可以让用户指定日期的分割符。一个简单的Regex是:/d/d./d/d./d/d这个看起来可以实现。它会很好的匹配04/09/07。问题是: 04409407也会被匹配。因为第三个4和第五个4都会被“.”匹配。这不是我们想要得结果。

/d/d[-/.]/d/d[-/.]/d/d是一个比上面的好的一个方法,用户可以指定“-”,“.”,“/”作为日期的分割符。因为“.”在字符集中不表示一个特殊字符,所以我们不需要在“.”之前加”/”。

但这个方法还不完美,它会匹配 99/99/99 , [0-1]/d[-/.][0-3]/d[-/.]/d/d也许会好一些。虽然它仍旧会匹配19/39/99, 。方法够用就好了,不必追求完美,如果这个是用来验证用户需求,可能还需要改进,如果只是用来分析一段code,或许已经足够了。

如果我们要匹配一段带双引号的字符串。听起来很容易,我们可以在两个双引号之间放任意多个任意字符。Regex可能会这么写:“.*”,这个会匹配put  a “string” between double quotes.结果是对的,但是如果去匹配“"string one” and “string two””则得到的结果会是 “string one” and “string two” 。这不是我们要的结果。

所以这里我们可以用否定字符集来代替“[^”/r/n]*”

3.1.10用 “|”表示选择

前面已经讲过,用字符集可以匹配很多字符其中的一个,替换的作用稍有不同。

如果需要匹配 cat 或者 dog,可以这样写:cat|dog,也可以添加很多:cat|dog|mouse|fish。

但是注意:“|”是正则表达式中优先级最低的操作符。Regex解释器在匹配的时候,要么匹配“|”左边的所有,要么匹配“|”右边的所有。

3.1.11用 “()”表示分组

可以使用圆括号来限制选择的范围。

上面的例子,如果想要限制替换,可以使用“()”符号。

比如:

如果我们要匹配整个词而不是一个词的一部分。Regex可以这样写:/b(cat|dog)/b。

这告诉regex解释器先去寻找一个边界,然后要么是cat,要么是dog,然后在去寻找一个边界。如果忽略掉括号,regex解释器会这样来匹配:要么是cat跟在一个边界的后面,要么是dog后面有一个边界。

3.1.12 “?”的补充说明

“?”除了表示重复之外,还表示可选。

例如:colou?r,会匹配color和colour。

用括号括起来的表示这組是一个可选的项目。

例如:Nov(ember)?会匹配Nov和November。

 

用“?”标记起来,等于告诉regex解释器有两种选项:要么匹配括起来的,要么不匹配。但是,Regex解释器总会首先去匹配括起来的部分,只有当这个失败了,才会当做忽略处理。

效果就是,如果用Feb 23(rd)?去匹配Today is Feb 23rd, 2004,结果总是Feb 23rd,而不是Feb 23。

 “?”也称作“懒元字符”,因为它总是尽可能的少的去匹配。

3.1.13给正则表达式添加注释

可以这样给正则表达式添加注释:

(?#comment here)

3.1.14操作符的运算优先级

Symbol

Function

Memo

/

转义符

 

(), (?:), (?=), []

括号

 

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

限定符

 

^, $, /anymetacharacter

定位符

 

|

 

 

3.2 高级话题

这里会讨论一些稍微复杂一些的主题,比如backreference(反向引用),lookround,ifelsethen等等。

3.2.1反向引用

()除了把regex括起来以外,还可以创建反向引用。对一个正则表达式模式或部分模式两边添加圆括号将导致相关匹配存储到一个临时缓冲区中,所捕获的每个子匹配都按照在正则表达式模式中从左至右所遇到的内容存储。存储子匹配的缓冲区编号从 1 开始,连续编号直至最大 99 个子表达式。每个缓冲区都可以使用 '/n' 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。   可以使用非捕获元字符 '?:', '?=', or '?!' 来忽略对相关匹配的保存。

例如:

Set(Value)?会匹配Set和SetValue。第一种情况下,/1的反向引用会是空,因为set没有匹配value。第二种情况下,/1的反向引用的值会变为value。

如果不想创建反向引用,可以使用特殊符号“:”,比如Set(?:Value)?。

使用反向引用

例如:我们要匹配一个html标记,和两个标记之间的内容。

我们可以这样写:<([A-Z][A-Z0-9]*)[^>]*>.*?。

首先创建一个[A-Z][A-Z0-9]的引用,然后后面用到这个引用。

注意:引用中不能引用自己。

 

正则表达式一个最重要的特性就是将匹配成功的模式的某部分进行存储供以后使用这一能力。请回想一下,对一个正则表达式模式或部分模式两边添加圆括号将导致这部分表达式存储到一个临时缓冲区中。可以使用非捕获元字符 '?:', '?=', or '?!' 来忽略对这部分正则表达式的保存。

所捕获的每个子匹配都按照在正则表达式模式中从左至右所遇到的内容存储。存储子匹配的缓冲区编号从 1 开始,连续编号直至最大 99 个子表达式。每个缓冲区都可以使用 '/n' 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。

反向引用一个最简单,最有用的应用是提供了确定文字中连续出现两个相同单词的位置的能力。请看下面的句子:

Is is the cost of of gasoline going up up?

根据所写内容,上面的句子明显存在单词多次重复的问题。如果能有一种方法无需查找每个单词的重复现象就能修改该句子就好了。下面的正则表达式就可以实现这一功能。

/b([a-z]+) /1/b

在这个示例中,子表达式就是圆括号之间的每一项。所捕获的表达式包括一个或多个字母字符,即由[a-z]+ 所指定的。该正则表达式的第二部分是对前面所捕获的子匹配的引用,也就是由附加表达式所匹配的第二次出现的单词。'/1'用来指定第一个子匹配。单词边界元字符确保只检测单独的单词。如果不这样,则诸如 "is issued" 或 "this is" 这样的短语都会被该表达式不正确地识别。

3.2.2在正则表达式中指定模式option

可以在正则表达式中指定匹配模式

Symbol

Function

Memo

i

区分大小写

前面加“-”表示关闭选项

s

单行模式匹配

 

M

多行模式匹配

 

 

语法为(?ism)

可以只对表达式的一部分使用模式,有效范围为从这个位置起直到碰到下一个模式符为止。

也可以在前面加上“-”表示关闭这个选项。

比如(?i-sm),表示区分大小写,关闭单行模式,打开多行模式。

3.2.3 Lookaround断言

Perl5新引进了一种构造,分别为Lookahead和Lookbeehind。它们也被称作“0宽度断言”。说它们是“0宽度”是因为它们和定位符差不多,都匹配的是一行或一个词的开始或结束。不同的地方是Lookahaed和Lookbehind匹配的是一个字符,而不是一个位置,但是却返回的不是匹配的字符结果,而是返回匹配的结果:匹配还是不匹配。这也是为什么称作它们是“断言”。它们不关心匹配结果是什么,它们只用来断言这个匹配结果有没有可能。

正向和反向的Lookahead

正向Lookahead的语法为:(?=Regex)

反向Lookahead的语法为:(?!Regex)

前面我们的例子q[^u]表示的意义是:‘q’后面的字符可以是除了u以外的所有字符”。但是,如果我们要得到的结果是:‘q’后面不是’u’,注意,不是:’q’后面的字符不是’u’。(q后面可以什么也没有,而字符集必须匹配一个字符),在这种情况下,我们就必须使用反向lookahead断言。可以这样写:q(?!u)。它的匹配结果就是: ‘q’后面不是’u’。

正向lookahead断言q(?=u)匹配的结果就是:‘q’后面是’u’。

重要:

可以在lookahead中使用任何合法的正则表达式,但是在lookbehind中就不可以。

Lookahead虽然被()括起来,但它并不创建反向引用。如果想要把断言中的匹配结果存起来,必须单独使用(),像这样:(?=(regex))。

 

正向和反向的Lookbehind

正向Lookbehind的语法为:(?<=Regex)

反向Lookbehind的语法为:(?

描述

查找html中的注释

匹配的例子

不匹配的例子

this text has been removed

 

查找html中的特定文件(swf.jpg.gif…)

表达式

<[^>]*/n?.*=("|')?(.*/.jpg)("|')?.*/n?[^<]*>

描述

查找html中的特定文件(swf.jpg.gif…)

把jpg换为gif,即是查找所有的gif文件。

匹配的例子

不匹配的例子

= img.jpg

日期和时间验证 日期验证

表达式

^(?:(?:(?:(?:(?:1[6-9]|[2-9]/d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(//|-|/.)(?:0?2/1(?:29)))|(?:(?:(?:1[6-9]|[2-9]/d)?/d{2})(//|-|/.)(?:(?:(?:0?[13578]|1[02])/2(?:31))|(?:(?:0?[1,3-9]|1[0-2])/2(29|30))|(?:(?:0?[1-9])|(?:1[0-2]))/2(?:0?[1-9]|1/d|2[0-8]))))$

描述

验证格式为y/m/d的日期从1600/1/1 - 9999/12/31的日期

匹配的例子

04/2/29

2002-4-30

02.10.31

不匹配的例子

2003/2/29

02.4.31

00/00/00

 

日期和时间验证

表达式

^(?=/d)(?:(?:(?:(?:(?:0?[13578]|1[02])(//|-|/.)31)/1|(?:(?:0?[1,3-9]|1[0-2])(//|-|/.)(?:29|30)/2))(?:(?:1[6-9]|[2-9]/d)?/d{2})|(?:0?2(//|-|/.)29/3(?:(?:(?:1[6-9]|[2-9]/d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))|(?:(?:0?[1-9])|(?:1[0-2]))(//|-|/.)(?:0?[1-9]|1/d|2[0-8])/4(?:(?:1[6-9]|[2-9]/d)?/d{2}))($|/ (?=/d)))?(((0?[1-9]|1[012])(:[0-5]/d){0,2}(/ [AP]M))|([01]/d|2[0-3])(:[0-5]/d){1,2})?$

描述

验证所有合法的日期和时间

匹配的例子

20:20

04/2/29

02.4.31

02.10.312002-4-30

02.10.31

不匹配的例子

2003/2/29

00/00/00

 

标准ANSI SQL日期验证

表达式

^((/d{2}(([02468][048])|([13579][26]))[/-///s]?((((0?[13578])|(1[02]))[/-///s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[/-///s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[/-///s]?((0?[1-9])|([1-2][0-9])))))|(/d{2}(([02468][1235679])|([13579][01345789]))[/-///s]?((((0?[13578])|(1[02]))[/-///s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[/-///s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[/-///s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(/s(((0?[1-9])|(1[0-2]))/:([0-5][0-9])((/s)|(/:([0-5][0-9])/s))([AM|PM|am|pm]{2,2})))?$

描述

匹配ANSI SQL的日期格式:YYYY-mm-dd hh:mi:ss am/pm

包括检查从1901-2099是否是闰年。

匹配的例子

2004-2-29

2004-02-29 10:29:39 pm

2004/12/31

不匹配的例子

04-2-29

04-02-29 10:29:39 pm

04/12/31

其他 匹配字体

表达式

^(/d)(/d)*( )*(px|PX|Px|pX|pt|PT|Pt|pT|)$

描述

查找字体的后缀

 

匹配的例子

1px

100 PT

20Px

不匹配的例子

1abc

px

1 sdfs

 

匹配MD5哈西字符串

表达式

^(/d)(/d)*( )*(px|PX|Px|pX|pt|PT|Pt|pT|)$

描述

^([a-z0-9]{32})$

匹配的例子

790d2cf6ada1937726c17f1ef41ab125

不匹配的例子

790D2CF6ADA1937726C17F1EF41AB125

Regex的相关工具和word文档可以在这里找到。://xafile/Share/Public/Bond/Regex

 

 

PS:

这个列表会一直更新的,希望大家也能多多支持。把看到的有用的Regex都贴进来。

J

Regular Expressions (3) ---- Using Regex in .NET

看这篇文章之前,假定你已经了解了有关正则表达式的一些知识,并且知道如何去应用它。本篇文章只介绍如何在.NET中使用正则表达式。

  最后是一个应用正则表达式的给VB程序语法加亮的小程序。

 

 

名称空间和相关的类

.NET中所有和正则表达式相关的类都定义在System.Text.RegularExpressions名称空间下。

分别是:

Class

Description

Regex

不可变的(只读)的正则表达式的实例,包括一些静态方法

Capture

包含单个子表达式匹配的结果,不能实例化,必须通过Group和Match来访问。

CaptureCollection

Capture的序列

Group

一组表达式匹配的结果,由Capture继承而来

GroupCollection

Group的序列

Match

一个正则表达式的匹配结果,由Group继承而来

MatchCollection

Match的序列

  下面用图和例子说明各个类之间的关系:

例:

如上图:

匹配的字符串是:”xgraygreyxgreyxgray”

正则表达式是:(gr[ae])y

表示匹配”gray”或者”grey”一次或n次。

  从生成的匹配树可以看到:

总共找到了三个匹配。每个匹配的值分别为:graygray,gray,grey。

以第一个匹配为例:

匹配一中共包括两个组:每个组的值分别为:graygrey,grey。

第一个组只有一个捕获结果,就是graygrey。

第二组有两个捕获结果,分别为gray和grey。

下面说明这些类的详细作用:

Match:

Match表示的是一个正则表达式的匹配操作。

如上例:

(Gr[ae]y)+得到三个Match结果。分别是graygrey,gray,grey。

这等于是正则表达式解释器把(gr[ae]y)+吃拆成了(gr[ae]y)+,(gray)+和(grey)+三个单独的子表达式。

每个子表达式对应一个Match结果。

Regex

Result

(gr[ae]y)+

Graygrey

(gray)+

Gray

(grey)+

Grey

MatchCollection

MatchCollection表示的就是所有的字表达式的Match结果的集合。

可以通过遍历Matchs的集合来访问各个子表达式的Match结果。

For each m as Match in Regex.Matches(“graygrey”, (gr[ae]y)+”)

            ‘ Use match result here.

Next

Group:

每个子表达式默认就是一个组。所以子表达式的所有组的结果都保存在第一个组中,这也是为什么每个Match的结果和第一个Group的结果是一样的,因为它们就是一个。

在.NET中,用括号括起来的子表达式表示这是一个组。

可以通过(?<groupName><子表达式>)来显示的给组命名。

比如:

Regex r = new Regex(“(? abc)+”)。就定义了一个组,名字为g1。

在程序中,我们可以通过组命来访问组的匹配结果。

Dim m As Match = r.Match("xxabcabc")

Dim g1 As Group = m.Groups(“g1”)

GroupCollection

GroupCollection表示一个Match中Group的集合。

可以通过组命或者索引来访问一个组。

  Catpure:

Capture中保存的是每一个子表达式的最小匹配结果,它相当于是原子匹配,比如a匹配a,则结果a就保存在capture中,group的结果只是所的capture结果的组合。

所以如果一个匹配只有一个group,这个group中又只有一个capture,则这个capture的结果就是整个Match的结果。

CaptureCollection

Capture的序列。

VBHightDemo

下面介绍一下这个应用正则表达式给VB语法加亮的程序。

这个程序的原理就是根据正则表达式分析每一行字符串,根据匹配结果,把相应的字符的颜色改变。

关键的地方就是拿到组建的正则表达式。

Private VBImports As Regex = New Regex("(? RegexOptions.Compiled)

    Private QuotedString As Regex = New Regex("""" & "[^""]*" & """", RegexOptions.Compiled)

    Private VBComment As Regex = New Regex("'.*")

    Private EmptyLine As Regex = New Regex("^//s*//Z", RegexOptions.Compiled)

    Private VBRegion As Regex = New Regex("(#region|#end region){1}", RegexOptions.Compiled)

      '-- use lookbehind, keywords can not follow by a '.' or a characotr

    Dim aa As String = "(?<![/./w])(as|boolean|break|byte|byval|byref|" _

                                & "case|catch|char|checked|class|const|continue|" _

                                & "decimal|dim|default|delegate|double|else|" _

                                & "enum|end|event|exit|explicit|extern|false|each|" _

                                & "float|friend|for|goto|if|implicit|inherits|" _

                                & "integer|interface|internal|is|lock|long|" _

                                & "namespace|new|next|overrides|overloads|object|operator|out|" _

                                & "override|params|private|protected|" _

                                & "public|readonly|ref|return|sbyte|sealed|" _

                                & "short|static|string|sub|" _

                                & "structure|switch|me|mybase|throw|true|try|typeof|" _

                                & "uint|ulong|unchecked|ushort|using|" _

                                & "while|withevents){1}[^/w]"

    Private VBKeyWords As Regex = New Regex(aa, RegexOptions.Compiled)

    Private SystemKeyWords As Regex = New Regex("(application|console|environment|gc|threadpool|math){1}", RegexOptions.Compiled)

Private Brackets As Regex = New Regex("(/{|/[|/(|/}|/]|/))", RegexOptions.Compiled)

在匹配的时候,可以给指定匹配的选项,比如忽略大小写,单行还是多行等等。

然后遍历并加亮匹配的结果就可以了。

For Each m As Match In regex.Matches(s)

       Me.ColorString(start + m.Groups(0).Index, m.Groups(0).Length, color)

Next

因为组中保存的就是所有capture的组合的结果,所以只加亮groups(0)中的字符串就够了,不需要再重复处理group中captures的值。

 

不正之处还请多多指正。

:)

 

If the source code needed, plase mail to me: etmonitor@msn.com.

关注
打赏
1688896170
查看更多评论

暂无认证

  • 0浏览

    0关注

    108697博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文
立即登录/注册

微信扫码登录

0.4965s