轻松学习正则表达式Word文档格式.docx
《轻松学习正则表达式Word文档格式.docx》由会员分享,可在线阅读,更多相关《轻松学习正则表达式Word文档格式.docx(9页珍藏版)》请在冰豆网上搜索。
这个表达式将只匹配完整的拼写为“elvis”的单词,无论是小写的还是大写的情况。
假设你想要找到所有这样的行,在其中单词“elvis”后面都跟着单词“alive”。
句点或者点“.”是一个特殊代码匹配除了换行符之外的任何字符。
星号“*”表示重复前面的部分有必要的次数以保证能够有一个匹配。
这样,“.*”表示“匹配除了换行符之外的任意数目的字符”。
现在建立一个表示“搜索在同一行内后面跟着单词‘alive’的单词‘elvis’”的表达式就是一件简单的事了。
3.\belvis\b.*\balive\b--Findtextwith"
elvis"
followedby"
alive"
仅仅使用几个特殊字符我们就开始创建功能强大的正则表达式了,而且它们已经开始变得难以被我们人类理解了。
让我们看看另一个例子。
确定电话号码的合法性
假设你的web页面收集顾客的7位电话号码,而且你希望验证输入的电话号码是正确的格式,“xxx-xxxx”,这里每个“x”是一个数字。
下面的表达式将搜索整个文本寻找这样的一个字符串:
4.\b\d\d\d-\d\d\d\d--Findseven-digitphonenumber
每个“\d”表示“匹配任何单个数字”。
“-”没有特殊的意义并且按照字面解释,匹配一个连字符。
要避免繁琐的重复,我们可以使用一个含有相同含义的速记符:
5.\b\d{3}-\d{4}--Findseven-digitphonenumberabetterway
“\d”后面的“{3}”表示“重复前面的字符三次”。
.NET正则表达式的基础
让我们探索一下.NET中正则表达式的基础
特殊字符
你应该知道几个有特殊意义的字符。
你已经见过了“\b”,“.”,“*”,和“\d”。
要匹配任何空白字符,像空格,制表符和换行符,使用“\s”。
相似地,“\w”匹配任何字母数字字符。
让我们尝试更多的例子:
6.\ba\w*\b--Findwordsthatstartwiththelettera
这个搜索一个单词的开头(\b),然后是一个字母“a”,接着是任意次数重复的字母数字字符(\w*),最后是一个单词的结尾(\b)。
7.\d+--Findrepeatedstringsofdigits
这里,“+”与“*”是相似的,除了它需要至少一次重复。
8.\b\w{6}\b--Findsixletterwords
在Expresso中测试这几个表达式,然后实践创建你自己的表达式。
下面是一个说明有特殊含义的字符的表格:
.匹配除换行符外的任何字符
\w匹配任何字母数字字符
\s匹配任何空白字符
\d匹配任何数字
\b匹配一个单词的开始或结尾
^匹配字符串的开始
$匹配字字符串的结尾
表1正则表达式的常用特殊字符
开始阶段
特殊字符“^”和“$”被用来搜索那些必须以一些文本开头和(或)以一些文本结尾的文本。
特别是在验证输入时特别有用,在这些验证中,输入的整个文本必须要匹配一个模式。
例如,要验证一个7位电话号码,你可能要用:
9.^\d{3}-\d{4}$--Validateaseven-digitphonenumber
这是和第5个例子一样的,但是强迫它符合整个文本字符串,匹配文本的头尾之外没有其他字符。
通过在.NET中设置“Multiline”选项,“^”和“$”改变他们的意义为匹配一行文本的起点和结束,而不是整个正文字符串。
Expresso的例子使用这个选项。
换码字符
当你想要匹配这些特殊字符中的一个时会产生一个错误,像“^”或者“$”。
使用反斜线符号来去掉它们的特殊意义。
这样,“\^”,“\.”,和“\\”,分别匹配文本字符“^”,“.”,和“\”。
重复
你已经见过了“{3}”和“*”可以指定一个单独字符的重复次数。
稍后,你会看到相同的语法怎样用来重复整个子表达式。
此外还有其他几种方法来指定一个重复,如下表所示:
*重复任意次数
+重复一次或多次
?
重复一次或多次
{n}重复n次
{n,m}重复最少n次,最多m次
{n,}重复最少n次
表2常用量词
让我们试试几个例子:
10.\b\w{5,6}\b--Findallfiveandsixletterwords
11.\b\d{3}\s\d{3}-\d{4}--Findtendigitphonenumbers
12.\d{3}-\d{2}-\d{4}--Socialsecuritynumber
13.^\w*--Thefirstwordinthelineorinthetext
在设置和不设置“Multiline”选项的时试试最后一个例子,它改变了“^”的含义。
字符集合
搜索字母数字字符,数字,和空白字符是容易的,但如果你需要搜索一个字符集合中的任意字符时怎么办?
这可以通过在方括号中列出想要的字符来轻松的解决。
这样,“[aeiou]”就能匹配任意韵母,而“[.?
!
]”就匹配句子末尾的标点。
在这个例子中,注意“.”和“?
”在方括号中都失去了他们的特殊意义而被解释为文本含义。
我们也可以指定一个范围的字符,所以“[a-z0-9]”表示“匹配任何小写字母或者任何数字”。
让我们试试一个搜索电话号码的更加复杂的表达式:
14.\(?
\d{3}[)]\s?
\d{3}[-]\d{4}Atendigitphonenumber
这个表达式将会搜索几种格式的电话号码,像“(800)325-3535”或者“6505551212”。
“\(?
”搜索0个或1个左圆括号,“[)]”搜索一个右圆括号或者一个空格。
“\s?
”搜索0个或一个空白字符。
不幸的是,它也会找到像“650)555-1212”这样括号没有去掉的情况。
在下面,你会看到怎样用可选项解决这个问题。
否定
有些时候我们需要搜索一个字符,它不是一个很容易定义的字符集合的成员。
下面的表格说明了这种字符怎样指定:
\W匹配任何非字母数字字符
\S匹配任何非空白字符
\D匹配任何非数字字符
\B匹配非单词开始或结束的位置
[^x]匹配任何非x字符
[^aeiou]匹配任何不在aeiou中的字符
表3怎样指定你不想要东西
15.\S+--Allstringsthatdonotcontainwhitespacecharacters
后面,我们会看到怎样使用“lookahead”和“lookbehind”来搜索缺少更加复杂的模式的情况。
可选项
要从几个可选项中选择,允许符合任何一个的匹配,使用竖杠“|”来分隔可选项。
例如,邮政编码有两种,一个是5位的,另一个是9位的加一个连字符。
我们可以使用下面的表达式找到任何一种:
16.\b\d{5}-\d{4}\b|\b\d{5}\b--FiveandninedigitZipCodes
当使用可选项时,顺序是很重要的因为匹配算法将试图先匹配最左面的选择。
如果这个例子中的顺序颠倒过来,表达式将只能找到5位的邮政编码,而不会找到9位的。
我们可以使用可选项来改进十位电话号码的表达式,允许包含区码无论是通过空白字符还是连字符划分的:
17.(\(\d{3}\)|\d{3})\s?
\d{3}[-]\d{4}--Tendigitphonenumbers,abetterway
分组
圆括号可以用来划分一个子表达式来允许重复或者其他特殊的处理,例如:
18.(\d{1,3}\.){3}\d{1,3}--AsimpleIPaddressfinder
表达式的第一部分搜索后面跟着一个“\.”的一个一位到三位的数字。
这被放在圆括号中并且通过使用修饰符“{3}”被重复三次,后面跟着与之前一样的表达式而不带后缀部分。
不幸的是,这个例子允许IP地址中被分隔的部分是任意的一位,两位,或三位数字,尽管一个合法的IP地址不能有大于255的数字。
要是能够算术比较一个获取的数字N使N<
256就好了,但是只用正则表达式是不能够办到的。
下一个例子使用模式匹配测试了基于第一位数字的多种可选项来保证限制数字的取值范围。
这表明一个表达式会变得很笨重,尽管搜索模式的描述是简单的。
19.((2[0-4]\d|25[0-5]|[01]?
\d\d?
)\.){3}(2[0-4]\d|25[0-5]|[01]?
)--IPfinder
一个“回引”用来搜索前面被一个分组捕获的已匹配文本的再现。
例如,“\1”表示“匹配分组1中已捕获到的文本”。
下面是一个例子:
20.\b(\w+)\b\s*\1\b--Findrepeatedwords
它的运行过程是先捕获一个分组1中“(\w+)”表示的至少包含一个字母数字字符的字符串,但仅当它是一个单词的开始或结束字符时才行。
然后它搜索任意数量的空白字符“\s*”后跟以被捕获的文本“\1”结尾的单词。
在上面的例子中,想要替换分组“(\w+)”这种写法,我们可以把它写成“(?
<
Word>
\w+)”来给这个分组命名为“Word”。
一个对这个分组的回引可以写成“\k<
”。
试试下面的例子:
21.\b(?
\w+)\b\s*\k<
\b--Capturerepeatedwordinanamedgroup
通过使用圆括号,有很多可用的特殊用途的语法元素。
一些最常用的归纳如下面这张表格:
捕获
(exp)匹配exp并且在一个自动计数的分组中捕获它
(?
name>
exp)匹配exp并且在一个命名的分组中捕获它
:
exp)匹配exp并且不捕获它
察看
=exp)匹配任何后缀exp之前的位置
=exp)匹配任何前缀exp之后的位置
exp)匹配任何未找到的后缀exp之后的位置
exp)匹配任何未找到的前缀exp之前的位置
评论
#comment)评论
表4常用分组结构
前两个我们已经说过了。
第三个“(?
exp)”不会改变匹配行为,它只是不像前两个那样捕获已命名的或者计数的分组。
确定察看(PositiveLookaround)
下面四个是所谓的前向或后向断言。
它们从当前的匹配向前或向后寻找需要的东西而不在匹配中包含它们。
这些表达式匹配一个类似于“^”或“\b”的位置而不匹配任何文本,理解这个是很重要的。
由于这个原因,他们也被称为“零宽度断言”。
最好用例子来解释它们:
“(?
=exp)”是“零宽度确定前向断言”。
它匹配一个文本中在给定后缀之前的位置,但不在匹配中包含这个后缀:
22.\b\w+(?
=ing\b)--Thebeginningofwordsendingwith"
ing"
=exp)”是“零宽度确定后向断言”。
它匹配在给定前缀后面的位置,但不在匹配中包含这个前缀:
23.(?
=\bre)\w+\b--Theendofwordsstartingwith"
re"
下面这个例子可以用来重复向三位数为一组的数字中插入逗号的例子:
24.(?
=\d)\d{3}\b--Threedigitsattheendofaword,precededbyadigit
下面是一个同时搜索前缀和后缀的例子:
25.(?
=\s)\w+(?
=\s)--Alphanumericstringsboundedbywhitespace
否定察看(NegativeLookaround)
之前,我说明了怎样搜索一个不是特定字符或一个字符集合的成员的字符。
那么如果我们想要简单的验证一个字符没有出现,但是不想匹配任何东西怎么办?
例如,如果我们想要搜索其中“q”不是后跟着“u”的单词怎么办?
我们可以尝试:
26.\b\w*q[^u]\w*\b--Wordswith"
q"
followedbyNOT"
u"
运行例子你就会看到如果“q”是一个单词的最后一个字母就不会匹配,比如“Iraq”。
这是因为“[^q]”总是匹配一个字符。
如果“q”是单词的最后一个字符,它会匹配后面跟着的空白字符,所以这个例子中表达式结束时匹配两个完整的单词。
否定察看可以解决这个问题,因为它匹配一个位置而不消耗任何文本。
与确定察看一样,它也可以用来匹配一个任意复杂的子表达式的位置,而不仅仅是一个字符。
我们现在可以做得更好:
27.\b\w*q(?
u)\w*\b--Searchforwordswith"
notfollowedby"
我们使用“零宽度否定前向断言”,“(?
exp)”,只有当后缀“exp”没有出现时它才成功。
下面是另一个例子:
28.\d{3}(?
\d)--Threedigitsnotfollowedbyanotherdigit
相似地,我们可以使用“(?
exp)”,“零宽度否定后向断言”,来搜索文本中的一个位置,这里前缀“exp”没有出现:
29.(?
[a-z])\w{7}--Stringsof7alphanumericsnotprecededbyaletterorspace
这里是另一个使用后向的例子:
30.(?
=<
(\w+)>
).*(?
\/\1>
)--TextbetweenHTMLtags
这个使用后向搜索一个HTML标记,而使用前向搜索对应的结束标记,这样,就能获得中间的文本而不包括两个标记。
评论
标点的另一个用法是使用“(?
#comment)”语法包含评论。
一个更好的办法是设置“IgnorePatternWhitespace”选项,它允许空白字符插入表达式然后当使用表达式时忽略它。
设置了这个选项之后,任何文本每行末尾在数字符号“#”后面的东西都被忽略。
例如,我们可以格式化先前的例子如下:
31.TextbetweenHTMLtags,withcomments
=#Searchforaprefix,butexcludeit
<
#Matchatagofalphanumericswithinanglebrackets
)#Endtheprefix
.*#Matchanytext
=#Searchforasuffix,butexcludeit
#Matchthepreviouslycapturedtagprecededby"
/"
)#Endthesuffix
贪婪与懒惰
当一个正则表达式有一个可以接受一个重复次数范围的量词(像“.*”),正常的行为是匹配尽可能多的字符。
考虑下面的正则表达式:
32.a.*b--Thelongeststringstartingwithaandendingwithb
如果这被用来搜索字符串“aabab”,它会匹配整个字符串“aabab”。
这被称为“贪婪”匹配。
有些时候,我们更喜欢“懒惰”匹配,其中一个匹配使用发现的最小数目的重复。
表2中所有的量词可以增加一个问号“?
”来转换到“懒惰”量词。
这样,“*?
”的意思就是“匹配任何数目的匹配,但是使用达到一个成功匹配的最小数目的重复”。
现在让我们试试懒惰版本的例子(32):
33.a.*?
b--Theshorteststringstartingwithaandendingwithb
如果我们把这个应用到相同的字符串“aabab”,它会先匹配“aab”然后匹配“ab”。
*?
重复任意次数,但尽可能少
+?
匹配一次或多次,但尽可能少
重复零次或多次,但尽可能少
{n,m}?
重复最少n次,但不多于m次,但尽可能少
{n,}?
重复最少n次,但尽可能少
表5懒惰量词
我们遗漏了什么?
我已经描述了很多元素,使用它们来开始创建正则表达式;
但是我还遗漏了一些东西,它们在下面的表中归纳出来。
这些中的很多都在项目文件中使用额外的例子说明了。
例子编号在这个表的左列中列出。
\a报警字符
\b通常是单词边界,但是在一个字符集合中它表示退格键
\t制表符
34\r回车
\v垂直制表符
\f分页符
35\n换行符
\eESC
36\nnnASCII码八进制数为nnn的字符
37\xnn十六进制数为nn的字符
38\unnnnUnicode码为nnnn的字符
39\cNControlN字符,例如回车(Ctrl-M)就是\cM
40\A字符串的开始(像^但是不依赖于多行选项)
41\Z字符串的结尾或者\n之前的字符串结尾(忽略多行)
\z字符串结尾(忽略多行)
42\G当前搜索的开始阶段
43\p{name}命名为name的Unicode类中的任何字符,例如\p{IsGreek}
(?
exp)贪婪子表达式,也被称为非回溯子表达式。
它只匹配一次然后就不再参与回溯。
44(?
x>
-<
y>
exp)or(?
exp)Balancinggroup.Thisiscomplicatedbutpowerful.Itallowsnamedcapturegroupstobemanipulatedonapushdown/popupstackandcanbeused,forexample,tosearchformatchingparentheses,whichisotherwisenotpossiblewithregularexpressions.Seetheexampleintheprojectfile.
45(?
im-nsx:
exp)正则表达式选项为子表达式exp
46(?
im-nsx)Changetheregularexpressionoptionsfortherestoftheenclosinggroup
(exp)yes|no)Thesubexpressionexpistreatedasazero-widthpositivelookahead.Ifitmatchesatthispoint,thesubexpressionyesbecomesthenextmatch,otherwisenoisused.
(exp)yes)Sameasabovebutwithanemptynoexpression
(name)yes|no)Thisisthesamesyntaxastheprecedingcase.Ifnameisavalidgroupname,theyesexpressionismatchedifthenamedgrouphadasuccessfulmatch,otherwisethenoexpressionismatched.
47(?
(name)yes)Sameasabovebutwithanemptynoexpression