文档库 最新最全的文档下载
当前位置:文档库 › 正则表达式

正则表达式

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

希望对大家会有所帮助。

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.举例会用以下格式:

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解释器也会

把他们忽略掉。

四种特殊字符的处理:

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

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

o“^”

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

o“]”

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

o“\”

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

o“-”

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

3.1.6预定义字符集

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

Regex Meaning Description

\d[0-9]所有数字

\w[a-zA-Z] 表示所有的字符,和文化字体有关\s[ \t\r\n] 空格,回车和tab。和文化字体有关

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

[\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次

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

[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的最后一个位置不包含换行符

词的边界

还有一种定位符匹配的是一个词(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)?。

使用反向引用

相关文档