您的位置:首页 > 其它

正则表达式

2008-01-31 09:45 351 查看
四种特殊字符的处理:
在字符集中要表示“]”,“^”和“-”需要在后面加上转义符“/”,来表示它们代表的分别是普通字符“]”,“^”和“-”。
也可以把它们放在一个不能表示特殊意义的位置,后一个方法比较好,因为他们不会影响可读性。

“^”

要想匹配一个“^”,可以把它放在除了紧跟“[”的任意一个位置。
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<space>+<space>2<space>=<space>3
匹配后面紧跟着一个数字的空白符
[/s/d]
1<space>+<space>2<space>=<space>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]+
846111
匹配数字
([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”就是可以组成词的字符,不包括非打印字符和回车换行。
有四种不同的位置被认为是词的边界:

第一个字符之前的位置,如果第一个字符是一个“word character”。

最后一个字符之后的位置,如果最后一个字符是一个“word character”。

介于词和非词之间的紧跟着词的位置。

介于非词和词之间的紧跟着非词的位置

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

/b匹配一个词的边界。
./b matches c in abc

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

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]*)[^>]*>.*?<//1>。
首先创建一个[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.3Lookaround断言
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的语法为:(?<!Regex)
用’<’来区分是Lookahead还是Lookbehind。

Lookbehind和lookahead有作用是相同的,但是它作用在string后面。它告诉Regex解释器暂时跳过lookbehind,先去匹配lookbehind后面的是否匹配,如果后面的匹配了,才去检查lookbehind中的断言。
(?<!a)b会匹配:’b’前面不是’a’。它不会匹配cab,但是会匹配一个单独的’b’或者bed、debt。
(?<=a)会匹配cab,但是不会匹配bed和debt。
重要:
不可以在Lookbehind中就不可以。
Lookbehind必须是定长的。所以‘?’‘*’‘+’不可以使用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: