正则表达式实例分解
趁有空发个贴子,数学公式正则表达式:
(?'kh'\()*([\-\+]){0,1}[0-9\.]+(?'-kh'\))*([\+\-\*\/]{1}(?'kh'\()*((?<=\()([\-\+]){0,1})?[0-9\.]+(?'-kh'\))*)+(?('kh')(?!))
匹配加减乘除数学公式,如:((1+2)-3*4)
(?'kh'\()*([\-\+]){0,1}[0-9\.]+(?'-kh'\))*([\+\-\*\/]{1}(?'kh'\()*((?<=\()([\-\+]){0,1})?[0-9\.]+(?'-kh'\))*)+(?('kh')(?!))
可以"("开始,压入堆栈统计括号数量,*代表可以出现0次或多次
(?'kh'\()*([\-\+]){0,1}[0-9\.]+(?'-kh'\))*([\+\-\*\/]{1}(?'kh'\()*((?<=\()([\-\+]){0,1})?[0-9\.]+(?'-kh'\))*)+(?('kh')(?!))
可以出现一次正负号
(?'kh'\()*([\-\+]){0,1}[0-9\.]+(?'-kh'\))*([\+\-\*\/]{1}(?'kh'\()*((?<=\()([\-\+]){0,1})?[0-9\.]+(?'-kh'\))*)+(?('kh')(?!))
0-9数字,一个或多个
(?'kh'\()*([\-\+]){0,1}[0-9\.]+(?'-kh'\))*([\+\-\*\/]{1}(?'kh'\()*((?<=\()([\-\+]){0,1})?[0-9\.]+(?'-kh'\))*)+(?('kh')(?!))
可以")"结束,弹出堆栈统计括号数量,*代表可以出现0次或多次
(?'kh'\()*([\-\+]){0,1}[0-9\.]+(?'-kh'\))*([\+\-\*\/]{1}(?'kh'\()*((?<=\()([\-\+]){0,1})?[0-9\.]+(?'-kh'\))*)+(?('kh')(?!))
橙色括号分组说明可以出现一次或多次,如公式1+2 ,这个括号里是匹配 2
红色要求+-*/出现一次
(?'kh'\()*([\-\+]){0,1}[0-9\.]+(?'-kh'\))*([\+\-\*\/]{1}(?'kh'\()*((?<=\()([\-\+]){0,1})?[0-9\.]+(?'-kh'\))*)+(?('kh')(?!))
判断括号开始时,可以有正负号,?代表使用懒惰匹配,即如:1+(((2-3)+4)+5)时,只匹配数字2前面的一个括号一次
(?'kh'\()*([\-\+]){0,1}[0-9\.]+(?'-kh'\))*([\+\-\*\/]{1}(?'kh'\()*((?<=\()([\-\+]){0,1})?[0-9\.]+(?'-kh'\))*)+(?('kh')(?!))
检查括号是否配对
--------------------编程问答-------------------- 技术贴。 --------------------编程问答-------------------- 整理的一个参考资料:
元字符 代码 说明
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束
字符转义
这时你就必须使用\来取消这些字符的特殊意义。因此,你应该使用\.和\*。当然,要查找\本身,你也得用\\.
重复 代码/语法 说明
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
字符类
我们也可以轻松地指定一个字符范围,像[0-9]代表的含意与\d就是完全一致的:一位数字,同理[a-z0-9A-Z_]也完全等同于\w(如果只考虑英文的话)。
反义 代码/语法 说明
\W 匹配任意不是字母,数字,下划线,汉字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非数字的字符
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符
替换
正则表达式里的替换指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用|把不同的规则分隔开。
分组
我们已经提到了怎么重复单个字符(直接在字符后面加上限定符就行了);但如果想要重复多个字符又该怎么办?你可以用小括号来指定子表达式(也叫做分组),然后你就可以指定这个子表达式的重复次数了,你也可以对子表达式进行其它一些操作(后面会有介绍)。
后向引用
使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2
后向引用用于重复搜索前面某个分组匹配的文本。例如,\1代表分组1匹配的文本。
捕获
(exp) 匹配exp,并捕获文本到自动命名的组里
(?<name>exp) 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)
(?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号
零宽断言
(?=exp) 匹配exp前面的位置
(?<=exp) 匹配exp后面的位置
(?!exp) 匹配后面跟的不是exp的位置
(?<!exp) 匹配前面不是exp的位置
注释
(?#comment) 这种类型的组不对正则表达式的处理产生任何影响,用于提供注释让人阅读
零宽断言
(?=exp)也叫零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。比如\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.时,它会匹配sing和danc。
(?<=exp)也叫零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式exp。比如(?<=\bre)\w+\b会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading。
负向零宽断言
零宽度负预测先行断言(?!exp),断言此位置的后面不能匹配表达式exp。例如:\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字;\b((?!abc)\w)+\b匹配不包含连续字符串abc的单词。
同理,我们可以用(?<!exp),零宽度正回顾后发断言来断言此位置的前面不能匹配表达式exp:(?<![a-z])\d{7}匹配前面不是小写字母的七位数字。
表5.懒惰限定符
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复
处理选项 名称 说明
IgnoreCase(忽略大小写) 匹配时不区分大小写。
Multiline(多行模式) 更改^和$的含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,$的精确含意是:匹配\n之前的位置以及字符串结束前的位置.)
Singleline(单行模式) 更改.的含义,使它与每一个字符匹配(包括换行符\n)。
IgnorePatternWhitespace(忽略空白) 忽略表达式中的非转义空白并启用由#标记的注释。
RightToLeft(从右向左查找) 匹配从右向左而不是从左向右进行。
ExplicitCapture(显式捕获) 仅捕获已被显式命名的组。
ECMAScript(JavaScript兼容模式) 使表达式的行为与它在JavaScript里的行为一致。
平衡组/递归匹配
(?'group') 把捕获的内容命名为group,并压入堆栈
(?'-group') 从堆栈上弹出最后压入堆栈的名为group的捕获内容,如果堆栈本来为空,则本分组的匹配失败
(?(group)yes|no) 如果堆栈上存在以名为group的捕获内容的话,继续匹配yes部分的表达式,否则继续匹配no部分
(?!) 零宽负向先行断言,由于没有后缀表达式,试图匹配总是失败
语法
\a 报警字符(打印它的效果是电脑嘀一声)
\b 通常是单词分界位置,但如果在字符类里使用代表退格
\t 制表符,Tab
\r 回车
\v 竖向制表符
\f 换页符
\n 换行符
\e Escape
\0nn ASCII代码中八进制代码为nn的字符
\xnn ASCII代码中十六进制代码为nn的字符
\unnnn Unicode代码中十六进制代码为nnnn的字符
\cN ASCII控制字符。比如\cC代表Ctrl+C
\A 字符串开头(类似^,但不受处理多行选项的影响)
\Z 字符串结尾或行尾(不受处理多行选项的影响)
\z 字符串结尾(类似$,但不受处理多行选项的影响)
\G 当前搜索的开头
\p{name} Unicode中命名为name的字符类,例如\p{IsGreek}
(?>exp) 贪婪子表达式
(?<x>-<y>exp) 平衡组
(?im-nsx:exp) 在子表达式exp中改变处理选项
(?im-nsx) 为表达式后面的部分改变处理选项
(?(exp)yes|no) 把exp当作零宽正向先行断言,如果在这个位置能匹配,使用yes作为此组的表达式;否则使用no
(?(exp)yes) 同上,只是使用空表达式作为no
(?(name)yes|no) 如果命名为name的组捕获到了内容,使用yes作为表达式;否则使用no
(?(name)yes) 同上,只是使用空表达式作为no
--------------------编程问答-------------------- 个人应用实例:
抓取网页代码中的标题:
(?<=<\s*\btitle\b[^>]*>)(.*)(?=<\s*/\btitle\b[^>]*>)
抓取网页代码中的关键字:
一,取出<meta keyword=....> :<\s*\bmeta\b[^>]*\bkeyword[^>]*>
二,取出content的值: \bcontent\b(\s)*=(\s)*([" + "\"']?)(.*)\3抓
\3是分组引用
取网页代码中的链接:
(?<=(<\s*\ba\b[^>]*\bhref\b(\s)?=))\s*(((" + "\"){1}([^" + "\"]*)(" + "\"){1})|(('){1}([^']*)('){1})|([^ >" + "\"']+[^ >]?))
--------------------编程问答-------------------- mark,
卖咖啡
卖瓜子
卖板凳
坐下学习 --------------------编程问答-------------------- 我还是拿杯茶喝下 --------------------编程问答-------------------- 关注学习 很好很强大.. --------------------编程问答-------------------- 这个得顶。 --------------------编程问答-------------------- --------------------编程问答-------------------- 技术贴...学习 --------------------编程问答-------------------- jinlaixueji --------------------编程问答-------------------- mark.... --------------------编程问答-------------------- --------------------编程问答-------------------- 路过,接分。 --------------------编程问答--------------------
论坛签名======================================================================
CrazyFor:你好!
截至 2011-03-31 09:53:11 前:
你已发帖 195 个, 未结贴 0 个;
结贴率为: 100.00%
--------------------编程问答-------------------- 学习了 ,多几个实用例子,更容易理解 --------------------编程问答-------------------- 学习 学习 --------------------编程问答-------------------- 收藏了! --------------------编程问答-------------------- 技术贴,学习了。 --------------------编程问答-------------------- 正则表达式看得真累! --------------------编程问答-------------------- 看看! --------------------编程问答-------------------- 正则表达式看起来就很难 --------------------编程问答-------------------- --------------------编程问答--------------------
瞄一眼。。。 --------------------编程问答-------------------- 平衡组老是参不透。。。 --------------------编程问答-------------------- 有鸭梨,学习学习 --------------------编程问答-------------------- 路过。。学习。。蹭分 --------------------编程问答-------------------- 好帖子 --------------------编程问答-------------------- 感谢楼主,正需要呢! --------------------编程问答-------------------- 收藏学习了 --------------------编程问答-------------------- 路过。。学习。。蹭分 --------------------编程问答-------------------- 学习下 --------------------编程问答-------------------- mark up --------------------编程问答-------------------- 10分贴。。接分。 --------------------编程问答-------------------- 正则 好东东啊。。 --------------------编程问答-------------------- 不错,学习 --------------------编程问答-------------------- 学习了 --------------------编程问答-------------------- 学习... --------------------编程问答-------------------- 好贴! --------------------编程问答-------------------- 学习! --------------------编程问答-------------------- 涉及不限定层次的嵌套,那这里应该使用了 .net 中的平衡组,呵呵。
不过对于数学公式之类的检查是否有效,我个人是不建议使用正则表达式来判断,应该使用语法、词法工具来做,呵呵。
当然了,如果是为了学习正则表达式,这样的是非常好地练习。 --------------------编程问答-------------------- 那个家伙要是被指派去调试这堆东西。。。估计马上抓狂。。 --------------------编程问答-------------------- 学习学习 --------------------编程问答-------------------- 好帖呀 --------------------编程问答-------------------- 强,这分明就是技术贴 --------------------编程问答-------------------- 貌似刚从phpchina上看到,难道是同一个人? --------------------编程问答--------------------
没有在其它地方发过,难道被盗版,嘿嘿~~
--------------------编程问答-------------------- 收藏了 --------------------编程问答-------------------- 很有用的,我收藏了 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 好帖子 --------------------编程问答-------------------- 哈哈 不错 --------------------编程问答-------------------- 哈哈,强势顶起! --------------------编程问答-------------------- 技术贴,顶 --------------------编程问答-------------------- --------------------编程问答-------------------- 很好的东西收藏了! --------------------编程问答-------------------- 难但是学会了很强大
--------------------编程问答-------------------- 这个在java上都通用不? --------------------编程问答-------------------- hao yun --------------------编程问答-------------------- 谢分享 --------------------编程问答-------------------- 鸭梨很大。。 --------------------编程问答-------------------- 谢谢~~ --------------------编程问答--------------------
不能,这其中涉及平衡组的语法,Java 目前版本还不支持。 --------------------编程问答-------------------- 这个好,顶一下~ --------------------编程问答-------------------- 学会了,可以去做动态采集了…… --------------------编程问答-------------------- 学习了 --------------------编程问答-------------------- 正则 很强大 --------------------编程问答-------------------- 强悍 我看得都晕~ --------------------编程问答-------------------- 好贴!!! --------------------编程问答-------------------- 看着眼晕,呵呵 --------------------编程问答-------------------- 我也来MARK --------------------编程问答--------------------
我也同意火龙果的观点
其实楼主这个正则,还有很多值得商榷的地方,简单说几点,欢迎讨论
目的是验证还是提取,无论是哪一种,用下面的字符串试下
(1+2
看看结果是什么,个人觉得分析结果为什么是这样,远比研究如何写这个正则有意思,当然,也更伤脑细胞
还有
([\-\+]){0,1})? 这里的{0,1}与后面的“?”作用是相同的,正则本身就很晦涩,同一正则中,出现多种写法,会进一步降低可读性
{1} 在正则中出现是让人很无奈的一件事
还有个别地方的捕获组用得没有道理的
无牙不敬业,看了也不研究,只来打酱油
个人比较喜欢研究正则的原理及应用,只可惜现在留给正则的时间是越来越少了 --------------------编程问答-------------------- up to you --------------------编程问答--------------------
多谢lxcnn指点,更正了括号配对问题和语法混淆问题。
(?'kh'\()*([\-\+])?[0-9\.]+(?'-kh'\))*([\+\-\*\/]{1}(?'kh'\()*((?<=\()([\-\+])?)?[0-9\.]+(?'-kh'\))*)+(?(kh)(?!)) --------------------编程问答-------------------- 我用于测试的数学公式:((1+(-100+(1*2-(91+(2-3+4)+100)-10*10)-(-100)))*7
可能还是会有bug的,天知道呢,呵呵~~~ --------------------编程问答-------------------- 之前的忘了删除字符串相加的一些字符
抓取网页代码中的关键字:
一,取出<meta keyword=....> :<\s*\bmeta\b[^>]*\bkeyword[^>]*>
二,取出content的值: \bcontent\b(\s)*=(\s)*([" + "\"']?)(.*)\3
更正为:\bcontent\b(\s)*=(\s)*([\"']?)(.*)\3
\3是分组引用
取网页代码中的链接:
(?<=(<\s*\ba\b[^>]*\bhref\b(\s)?=))\s*(((" + "\"){1}([^" + "\"]*)(" + "\"){1})|(('){1}([^']*)('){1})|([^ >" + "\"']+[^ >]?))
更正为:(?<=(<\s*\ba\b[^>]*\bhref\b(\s)?=))\s*(((\"){1}([^\"]*)(\"){1})|(('){1}([^']*)('){1})|([^ >\"']+[^ >]?))
--------------------编程问答-------------------- 看了头晕 --------------------编程问答-------------------- UP~~~~~~~~~ --------------------编程问答-------------------- 有用,得学学 --------------------编程问答-------------------- 很给力 非常强悍 定一个 --------------------编程问答-------------------- 开始看介绍还好,但一实践就完全 不会了 --------------------编程问答-------------------- 技术贴,学习了。 --------------------编程问答-------------------- 没有看懂 --------------------编程问答-------------------- 测试了下 不对怎么破啊~
补充:.NET技术 , 非技术区