正则表达式概述

2概念 给定一个正则表达式和另一个字符串,我们可以达到如下的目的: 1. 给定的字…

2概念

给定一个正则表达式和另一个字符串,我们可以达到如下的目的:

1. 给定的字符串是否符合正则表达式的过滤逻辑(称作“匹配”);

2. 可以通过正则表达式,从字符串中获取我们想要的特定部分。

正则表达式的特点是:

1. 灵活性、逻辑性和功能性非常的强;

2. 可以迅速地用极简单的方式达到字符串的复杂控制。

3. 对于刚接触的人来说,比较晦涩难懂。

3引擎

正则引擎主要可以分为两大类:一种是DFA,一种是NFA。这两种引擎都有了很久的历史(至今二十多年),当中也由这两种引擎产生了很多变体!于是POSIX的出台产生规范了不必要变体的继续产生。这样一来,主流的正则引擎又分为3类:一、DFA,二、传统型NFA,三、POSIX NFA。

POSIX NFA 引擎与传统的 NFA 引擎类似,不同的一点在于:在它们可以确保已找到了可能的最长的匹配之前,它们将继续回溯。因此,POSIX NFA 引擎的速度慢于传统的 NFA 引擎;并且在使用 POSIX NFA 时,您恐怕不会愿意在更改回溯搜索的顺序的情况下来支持较短的匹配搜索,而非较长的匹配搜索。

使用DFA引擎的程序主要有:awk,egrep,flex,lex,MySQL,Procmail等;

使用传统型NFA引擎的程序主要有:GNU Emacs,Java,ergp,less,more,.NET语言,PCRE library,Perl,PHP,Python,Ruby,sed,vi;

使用POSIX NFA引擎的程序主要有:mawk,Mortice Kern Systems’ utilities,GNU Emacs(使用时可以明确指定);

也有使用DFA/NFA混合的引擎:GNU awk,GNU grep/egrep,Tcl。

举例简单说明NFA与DFA工作的区别:

比如有字符串this is yansen’s blog,正则表达式为 /ya(msen|nsen|nsem)/ (不要在乎表达式怎么样,这里只是为了说明引擎间的工作区别)。 NFA工作方式如下,先在字符串中查找 y 然后匹配其后是否为 a ,如果是 a 则继续,查找其后是否为 m 如果不是则匹配其后是否为 n (此时淘汰msen选择支)。然后继续看其后是否依次为 s,e,接着测试是否为 n ,是 n 则匹配成功,不是则测试是否为 m 。为什么是 m ?因为 NFA 工作方式是以正则表达式为标准,反复测试字符串,这样同样一个字符串有可能被反复测试了很多次!

而DFA则不是如此,DFA会从 this 中 t 开始依次查找 y,定位到 y ,已知其后为 a ,则查看表达式是否有 a ,此处正好有 a 。然后字符串 a 后为 n ,DFA依次测试表达式,此时 msen 不符合要求淘汰。nsen 和 nsem 符合要求,然后DFA依次检查字符串,检测到sen 中的 n 时只有nsen 分支符合,则匹配成功!

由此可以看出来,两种引擎的工作方式完全不同,一个(NFA)以表达式为主导,一个(DFA)以文本为主导!一般而论,DFA引擎则搜索更快一些!但是NFA以表达式为主导,反而更容易操纵,因此一般程序员更偏爱NFA引擎! 两种引擎各有所长,而真正的引用则取决与你的需要以及所使用的语言!

4零宽断言

用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。最好还是拿例子来说明吧:

假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了),你可以这样查找需要在前面和里面添加逗号的部分:((?<=\d)\d{3})+\b,用它对xxxxxxxxxx进行查找时结果是xxxxxxxxxx

下面这个例子同时使用了这两种断言:(?<=\s)\d+(?=\s)匹配以空白符间隔的数字(再次强调,不包括这些空白符)

断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配。

5负向零宽

如果我们只是想要 确保某个字符没有出现,但并不想去匹配它时怎么办?例如,如果我们想查找这样的单词–它里面出现了字母q,但是q后面跟的不是字母u,我们可以尝试这样:

\b\w*q[^u]\w*\b匹配包含 后面不是字母u的字母q的单词。但是如果多做测试(或者你思维足够敏锐,直接就观察出来了),你会发现,如果q出单词的结尾的话,像 Iraq, Benq,这个表达式就会出错。这是因为[^u]总要匹配一个字符,所以如果q是单词的最后一个字符的话,后面的[^u]将会匹配q后面的单词分隔符(可能是空格,或者是句号或其它的什么),后面的\w*\b将会匹配下一个单词,于是\b\w*q[^u]\w*\b就能匹配整个Iraq fighting。负向零宽断言能解决这样的问题,因为它只匹配一个位置,并不 消费任何字符。,我们可以这样来解决这个问题:\b\w*q(?!u)\w*\b。

零宽度负预测先行断言(?!exp),断言此位置的后面不能匹配表达式exp。例如:\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字;\b((?!abc)\w)+\b匹配不包含连续字符串abc的单词。

同理,我们可以用(?<!exp),零宽度负回顾后发断言来断言此位置的前面不能匹配表达式exp:(?<![a-z])\d{7}匹配前面不是小写字母的七位数字。

请详细分析表达式(?<=<(\w+)>).*(?=<\/\1>),这个表达式最能表现零宽断言的真正用途。

一个更复杂的例子:(?<=<(\w+)>).*(?=<\/\1>)匹配不包含属性的简单HTML标签内里的内容。(?<=<(\w+)>)指定了这样的前缀:被尖括号括起来的单词(比如可能是<b>),然后是.*(任意的字符串),最后是一个后缀(?=<\/\1>)。注意后缀里的\/,它用到了前面提过的字符转义;\1则是一个反向引用,引用的正是捕获的第一组,前面的(\w+)匹配的内容,这样如果前缀实际上是<b>的话,后缀就是</b>了。整个表达式匹配的是<b>和</b>之间的内容(再次提醒,不包括前缀和后缀本身)。

6符号

he is arat

he is in a rut

the food is Rotten

I like root beer

grep r.t test.txt

有时候指定“除了×××都匹配”会比较容易达到目的,当抑扬字符(^)出方括号中时,它表示“排除”,例如要匹配he ,但是排除前面是t or s的情形(也就是the和she),可以使用:[^st]he。

例1

将所有方法foo(a,b,c)的实例改为foo(b,a,c)。这里a、b和c可以是任何提供给方法foo()的参数。也就是说我们要实现这样的转换:

之前 之后

foo(10,7,2) foo(7,10,2)

foo(x+13,y-2,10) foo(y-2,x+13,10)

foo( bar(8), x+y+z, 5) foo( x+y+z, bar(8), 5)

下面这条替换命令能够实现这一魔法:

:%s/foo(\([^,]*\),\([^,]*\),\([^)]*\))/foo(\2,\1,\3)/g

让我们把它打散来加以分析。写出这个表达式的基本思路是找出foo()和它的括号中的三个参数的位置。第一个参数是用这个表达式来识别的::\([^,]*\),我们可以从里向外来分析它:

[^,] 除了逗号之外的任何字符

[^,]* 0或者多个非逗号字符

\([^,]*\) 将这些非逗号字符标记为\1,这样可以在之后的替换模式表达式中引用它

正则表达式语法支持情况

7替换技巧

【1】 正则表达式应用——替换指定内容到行尾

【2】 正则表达式应用——数字替换

【5】 正则表达式应用——删除空行

【6】 正则表达式应用——实例应用

【1】正则表达式应用——替换指定内容到行尾

原始文本如下面两行

abc aaaaa

123 abc 444

希望每次遇到“abc”,则替换“abc”以及其后到行尾的内容为“abc efg”

即上面的文本最终替换为:

abc efg

123 abc efg

解决:

① 在替换对话框,查找内容里输入“abc.*”,替换内容输入为“abc efg”

其中,符号的含义如下:

“*” =匹配0次或更多

注意:其实就是正则表达式替换,这里只是把一些曾经提出的问题加以整理,单纯从正则表达式本身来说,就可以引申出成千上万种特例。

【2】正则表达式应用——数字替换

希望把

asdadas123asdasdas456asdasdasd789asdasd

替换为:

asdadas[123]asdasdas[456]asdasdasd[789]asdasd

在查找内容里面输入“([0-9])([0-9])([0-9])”,不含引号

“替换为:”里面输入“[\1\2\3]”,不含引号

####备注####:查找([0-9]+) 替换:[\1] 更简单通用些

范围为你所操作的范围,然后选择替换即可。

实际上这也是正则表达式的使用特例,“[0-9]”表示匹配0~9之间的任何特例,同样“[a-z]”就表示匹配a~z之间的任何特例

上面重复使用了“[0-9]”,表示连续出现的三个数字

括号用来选择原型,进行分组,替换时要用

“\1”代表第一个“[0-9]”对应的原型,“\2”代表第二个“[0-9]”对应的原型,依此类推

asdadas其它123其它asdasdas其它456其它asdasdasd其它789其它asdasd

功能增强:

如果将查找内容“[0-9][0-9][0-9]”改为“[0-9]*[0-9]”,对应1 或 123 或 12345 或 …

大家根据需要定制

相关内容还有很多,可以自己参考正则表达式的语法仔细研究一下

比如

12345 1265345

2345

需要删除每行末尾的“345”

这个也算正则表达式的用法,其实仔细看正则表达式应该比较简单,不过既然有这个问题提出,说明对正则表达式还得有个认识过程,解决方法如下

解决:

在查找内容里面输入“345$”

这里“$”表示从行尾匹配

如果从行首匹配,可以用“^”来实现,不过 EditPlus 有另一个功能可以很简单的删除行首的字符串

a. 选择要操作的行

b. 编辑-格式-删除行注释

【4】正则表达式应用——替换带有半角括号的多行

几百个网页中都有下面一段代码:

<script LANGUAGE="JavaScript1.1">

<!–

htmlAdWH('93163607', '728', '90');

//–>

</SCRIPT>

我想把它们都去掉,可是找了很多search & replace的软件,都是只能对“一行”进行操作。

EditPlus 打开几百个网页文件还是比较顺畅的,所以完全可以胜任这个工作。

“<script LANGUAGE="JavaScript1.1">\n<!–\nhtmlAdWH('93163607', '728', '90'.);\n//–>\n</SCRIPT>\n”

<script LANGUAGE="JavaScript1.1">\n<!–\nhtmlAdWH.'93163607', '728', '90'.;\n//–>\n</SCRIPT>\n

在替换对话框启用“正则表达式”选项,这时就可以完成替换了

补充:

对( ) 这样的特殊符号,应该用\( \)来表示,这也是很标准的regexp语法,可以写为

<script LANGUAGE="JavaScript1.1">\n<!–\nhtmlAdWH\('93163607', '728', '90'\);\n//–>\n</SCRIPT>\n

【5】正则表达式应用——删除空行

启动EditPlus,打开待处理的文本类型文件。

(6)选择“换行符”,插入“\n”,表示回车符。

【6】 正则表达式应用——实例应用

1.验证用户名和密码:("^[a-zA-Z]\w{5,15}$")正确格式:"[A-Z][a-z]_[0-9]"组成,并且第一个字必须为字母6~16位;

2.验证电话号码:("^(\d{3,4}-)\d{7,8}$")正确格式:xxx/xxxx-xxxxxxx/xxxxxxxx;

3.验证手机号码:"^1[3|4|5|8][0-9]\\d{8}$";

4.验证身份证号(15位或18位数字):"\\d{17}[[0-9],0-9xX]";

5.验证Email地址:("^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$");

6.只能输入由数字和26个英文字母组成的字符串:("^[A-Za-z0-9]+$") ;

7.整数或者小数:^[0-9]+\.{0,1}[0-9]{0,2}$

8.只能输入数字:"^[0-9]*$"。

9.只能输入n位的数字:"^\d{n}$"。

10.只能输入至少n位的数字:"^\d{n,}$"。

11.只能输入m~n位的数字:"^\d{m,n}$"。

12.只能输入零和非零开头的数字:"^(0|[1-9][0-9]*)$"。

13.只能输入有两位小数的正实数:"^[0-9]+(.[0-9]{2})?$"。

14.只能输入有1~3位小数的正实数:"^[0-9]+(.[0-9]{1,3})?$"。

15.只能输入非零的正整数:"^\+?[1-9][0-9]*$"。

16.只能输入非零的负整数:"^\-[1-9][]0-9"*$。

17.只能输入长度为3的字符:"^.{3}$"。

18.只能输入由26个英文字母组成的字符串:"^[A-Za-z]+$"。

19.只能输入由26个大写英文字母组成的字符串:"^[A-Z]+$"。

20.只能输入由26个小写英文字母组成的字符串:"^[a-z]+$"。

21.验证是否含有^%&',;=?$\"等字符:"[^%&',;=?$\x22]+"。

22.只能输入汉字:"^[\u4e00-\u9fa5]{0,}$"。

23.验证URL:"^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$"。

24.验证一年的12个月:"^(0?[1-9]|1[0-2])$"正确格式为:"01"~"09"和"1"~"12"。

25.验证一个月的31天:"^((0?[1-9])|((1|2)[0-9])|30|31)$"正确格式为;"01"~"09"和"1"~"31"。

26.获取日期正则表达式:\d{4}[年|\-|\.]\d{\1-\12}[月|\-|\.]\d{\1-\31}日?

评注:可用来匹配大多数年月日信息。

28.匹配空白行的正则表达式:\n\s*\r

评注:可以用来删除空白行

29.匹配HTML标记的正则表达式:<(\S*?)[^>]*>.*?</>|<.*? />

评注:网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力

31.匹配网址URL的正则表达式:[a-zA-z]+://[^\s]*

评注:网上流传的版本功能很有限,上面这个基本可以满足需求

评注:表单验证时很实用

33.匹配腾讯QQ号:[1-9][0-9]\{4,\}

34.匹配中国邮政编码:[1-9]\d{5}(?!\d)

评注:中国邮政编码为6位数字

35.匹配ip地址:((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)。

评注:提取ip地址时有用

Function IsRegu(Regu,s)

'正则表达式校验

If Regu="" Then

Exit Function

End if

Dim Re,Sre

Set Re = New RegExp

Re.Pattern = Regu

Sre = Re.Test(s)

If Sre = True Then

IsRegu = True

Else

IsRegu = False

End If

End Function

tmp=" "

if (IsRegu("\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*",tmp )) =false then

msgbox "E-mail地址不合法 !"

FieldCheck#N=false

end if

不同的语言(如PHP和JAVA)、相同语言的不同类库(如来自Sun的Java Regular Expression类库跟Apache Jakarta的正则表达式类库)间,用法会有所差别,在使用的时候,要注意这些差别。

8启示

(1) 心中时刻保持新颖想法,尝试用各种新办法来解决遇到的问题。对于遇到的问题,在用常规的解决思路无法解决或不能很好解决的时候,可以大胆探索尝试采用新的方法或思路来解决问题,说大点就是创新!没有新思路估计今天的正则表达式还要等几百年才能露现人间。

(2) 善于学习和借鉴前人的经验和成果,UNIX鼻祖Ken Thompson是什么样子的人?是被计算机界尊称为“UNIX之父”的大师级别的人物,大师都在不断思考从其它学科、其它知识领域的工作成果,来改进自己的工作或程序,事实也证明这样做取得巨大结果和后来的深远影响是事先谁也无法预估到的,我们在做一些事情或研究的时间,是否也考虑学习大师的优秀习惯?

(4) 养成独立思考的习惯。上学时候老师经常说人与动物的最大区别是人能思考。拉美洲有句关于“思考”的谚语是,不会思考的人是白痴,不肯思考的人是懒汉,不敢思考的人是奴隶。我想大家和我一样,既不愿做懒汉、奴隶,更不愿做白痴。所以相信正则分享网的朋友们一定会选择做一个“会思、肯思、敢思”的人。

9教程

正则表达式教程chm完整版是一本详细介绍了正则表达式的电子书教程,全书共分为8个小节,详细的讲述了正则表达式的定义,各种操作符的运算优先级,全部符号解释,正则表达式匹配规则,参考文献以及相关实例等,全书简明扼要,能够很好的帮助读者们正确常握学习好正则表达式,从而在软件编程中得到更好的发挥。 [6]

本文来自网络,不代表软粉网立场,转载请注明出处:https://www.rfff.net/p/5225.html

作者: HUI

发表评论

您的电子邮箱地址不会被公开。

返回顶部