论正则表达式的“贪婪”性(转)

本文通过实例详细解析了正则表达式的贪婪性特点,介绍了如何使用sed命令精确匹配目标字符串,特别是如何逐步调整模式串以准确获取指定括号内的内容。
论正则表达式的“贪婪”性(转)[@more@]

正则表达式是具有贪婪性的,我们从下面这例谈起:

已知str="uid=100(guest) gid=100(others) groups=10(users),11(floppy)"

现在想要得到这个字符串中的第一个括号内的值,即guest该怎么办?假设$str的括号外的内容是不固定的,不能依据uid之类的关键字或空格去查找,所依据的只能是找第一对括号内的内容。

很自然的我们想到用sed,因为sed具有很强的模式匹配的功能,而且能够将匹配的部分内容强行记下来用于输出。这样,我们就会想:

echo $str|sed 's/模式串/1/'

只要模式串写好了,在匹配的过程中把guest这个字符串抠出来,让sed记住,然后用1输出就可以了。怎么写这个模式串?

.*想要匹配"uid=100"

(...)告诉sed要查找括弧内的文本

(.*)让sed记住匹配内容的常用手段,这里匹配的.*将来就能用1取出来

.*想要匹配" gid=100(others) groups=10(users),11(floppy)"部分

于是我们就写成了echo $str|sed 's/.*((.*)).*/1/'

结果呢,得到的是"floppy",为什么?

正则表达式是有贪婪性的,它总是与最长的可能长度匹配,而且越是排在前面的通配符优先级越高。这一例,第一个.*可以匹配"uid=100(guest) gid=100(others) groups=10(users),11",仍然能保证后面通配符的匹配,那一对()匹配了floppy左右的括号,最后的.*自然是可有可无的,所以sed记住的就是floppy。

怎么办?我们必须打破正则表达式的贪吃性,用更明确的描述来实现这一点:

我们考虑如果在模式串中第一个.*中告诉sed这个.*是不能含有"("的,不久可以将.*限制到"uid=100"了吗?这个意思我们完全可以用[^(]*来表达,于是我们修订刚才的代码,变成:

echo $str|sed 's/[^(]*((.*)).*/1/'

似乎应该很好了,执行的结果却是"guest) gid=100(others) groups=10(users),11(floppy",为什么?

原来仍然是正则表达是的贪婪性在作怪,虽然我们有效的阻止了第一个.*的贪吃,但是我们对(.*)中的.*却未加限制,于是它尽可能匹配了"guest) gid=100(others) groups=10(users),11(floppy",还能保证后面".*"的匹配性。我们再作限制,告诉sed,(.*)中的.*不能含有"",让它跨不过guest:

echo $str|sed 's/[^(]*(([^)]*)).*/1/'

这回,输出结果终于是我们想要得"guest"了。

问题解决了,我们也了解了正则表达式(或说通配符)的贪婪性,于是就可以留个问题给大家,让大家自己体会体会:

怎么样取出str中第二对括号的内容"others"?

怎么样取出str中第三对括号的内容"users"?

怎么样取出str中第四对括号的内容"floppy"?(这个还用说吗,就利用正则表达式的贪婪性,我们最开始不就实现它了嘛)

又见michaelds的佳作。

俺来做作业。

str="uid=100(guest) gid=100(others) groups=10(users),11(floppy)"

echo $str|sed 's/[^(]*(([^)]*))[^(]*(([^)]*))[^(]*(([^)]*))[^(]*(([^)]*)

)/2/'

上式得到others,把2改成3,4可得到users和floppy

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/8225414/viewspace-944855/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/8225414/viewspace-944855/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值