PHP 正则 如何匹配不出现某段字符串的写法!(保留备份)
2011-09-13 17:43
501 查看
网友cfc4n问及关于(?!)的正则表达式问题。回答之后,顺便总结了一下Perl语言中如何匹配“不出现”某元素,贴在这里。
有如下文本,如何使用正则式,将其中不含color选项的item匹配出来?
新手容易提供这样的错误答案:
匹配是
返回正题,看个例子。如果要检测某字串是否含有good,当然要用
如果要检测某字串是否不含有good,可以用
这种匹配测试,较适合于在大段的字串中搜索某个简单的模式,然后对于匹配的结果作出两种不同的判断,非此即彼。虽然迅速干练,但是对于复杂情况的判断,还是有些累赘。
对于文章开始提出的问题而言,当然可以这样解决:先搜索所有的
输出结果是:
虽然也不错,但是它总是“宁可错杀不可错放”地找完所有可能项,再一一重新进行排除。能否一开始就先界定,我们要找的是不含color的item呢?排除型匹配正是为此而生。
不好意思,“排除型匹配”这个词是我生造的。其它的说法或许是“否定断言”,“否定环视”等等。后两者的命名,都是从匹配过程的角度出发;而此处命名,是从结果出发。具体说来,就是使用
这两个东东的使用方法类似,都是指,当前位置不出现某种模式。不同的是,
这里隆重推出Anrs同学翻译的教程:
环视一以及环视二。仔细阅读这两文章,彻底明白环视这两个概念,将会提升您的正则表达式功力。后文将建立在您已经理解环视这个概念的基础上。
闲话一句。既然使用“左边”和“右边”既形象又好懂,为什么没见过“左瞻”,“右瞻”,“左向”,“右向”,反而全是些“前瞻后瞻”,“正向逆向”这样的不好理解的说法呢?撕烤者也同有此问。我的理解是,或许是为了照顾阿语等从右向左书写的用户的习惯吧。无论如何,将从
描述当前位置(左侧或右侧)的模式,从而辅助判断正则式是否匹配,是环视的作用。它只描述,不消耗字符;只辅助判断,从不单独出现。这与
例子. 现在有许多与fanfou.com类似的网址。如何写一条正则表达式,来匹配域名含fanfou,但是TLS不是.com的模式?
答案:
以
fanfou主域名不可少;
.us),最长可为4位(如.info, .asia);
右侧边界同样重要,否则我们之前的{2,4}就白费了;
使用i表示不分大小写;这是域名的特征之一。
按照要求,一步步建立这条正则式。
该正则式匹配的是
在
正则式此时为
总体来说,环视相对于基本的元字符还是要抽象一些。不过一旦理解并掌握了它,就会发现它在精确匹配和替换时十分有用。上面的分析,希望有所帮助。如果您有类似的问题,欢迎提出。
Tags: exclude,
lookaround,
negate, perl
原文来自:http://iregex.org/blog/negate-match.html
问题
问题描述
有如下文本,如何使用正则式,将其中不含color选项的item匹配出来?1 2 3 4 5 6 7 8 | <item> color:red; </item> <item> size:12; number:45; type:good; </item> |
典型的错误答案
新手容易提供这样的错误答案:<item>.*?(?!color).*?</item>。其出发点是正确的:只有当color不出现在目标字串时,该匹配才是所需要的。事实上,这样的正则表达式不能如君所愿,它匹配所有的
<item>...</item>。这是为什么呢?
Perl之排除型匹配
最简单的排除型匹配
匹配是=~, 不匹配当然是
!~了。写到这里想到,在正则式中,凡是由
=组成的正则式符号,全可以使用
!来替代,以表现相反的意思。例如
(?=)与
(?!),
(?<=)与
(?<!),
=~与
!~。
返回正题,看个例子。如果要检测某字串是否含有good,当然要用
if ($string =~ /good/),如果
$string里有good则条件为真,否则为假;
如果要检测某字串是否不含有good,可以用
if ($string !~ /good/),如果
$string里没有good则条件为真,否则为假。
这种匹配测试,较适合于在大段的字串中搜索某个简单的模式,然后对于匹配的结果作出两种不同的判断,非此即彼。虽然迅速干练,但是对于复杂情况的判断,还是有些累赘。
对于文章开始提出的问题而言,当然可以这样解决:先搜索所有的
<item>...</item>,然后分别判断是否存在color项即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #!/usr/bin/perl -w my $text=<<END; <item> color:red; </item> <item> size:12; number:45; type:good; </item> END my @result = $text=~ m!<item>.*?</item>!sg; foreach $item (@result) { if ($item !~ /color/) { print "$item"; } } |
1 2 3 4 5 | <item> size:12; number:45; type:good; </item> |
排除型匹配
不好意思,“排除型匹配”这个词是我生造的。其它的说法或许是“否定断言”,“否定环视”等等。后两者的命名,都是从匹配过程的角度出发;而此处命名,是从结果出发。具体说来,就是使用(?!...)和
(?<!...)作为辅助条件判断,来简化正则表达式,方便快捷地找到符合要求的匹配。
这两个东东的使用方法类似,都是指,当前位置不出现某种模式。不同的是,
(?!...)是指当前位置的右边,而
(?<!)自然就是指左边了。
这里隆重推出Anrs同学翻译的教程:
环视一以及环视二。仔细阅读这两文章,彻底明白环视这两个概念,将会提升您的正则表达式功力。后文将建立在您已经理解环视这个概念的基础上。
闲话一句。既然使用“左边”和“右边”既形象又好懂,为什么没见过“左瞻”,“右瞻”,“左向”,“右向”,反而全是些“前瞻后瞻”,“正向逆向”这样的不好理解的说法呢?撕烤者也同有此问。我的理解是,或许是为了照顾阿语等从右向左书写的用户的习惯吧。无论如何,将从
^到
$的方向称之为“向前”总不会错。
描述当前位置(左侧或右侧)的模式,从而辅助判断正则式是否匹配,是环视的作用。它只描述,不消耗字符;只辅助判断,从不单独出现。这与
^和
$简直如出一辙。
一则例子
例子. 现在有许多与fanfou.com类似的网址。如何写一条正则表达式,来匹配域名含fanfou,但是TLS不是.com的模式?答案:
/\bfanfou\.(?!com)[a-z]{2,4}\b/i。分析这条正则表达式:
以
\b开始,明确字符边界;
fanfou主域名不可少;
\.匹配一个普通的点号;此处不要使用点号元字符;
(?!com)表示此处(即从
fanfou.的右边)不得出现com三个连续字符;
[a-z]{2,4}表示是2至4位的拉丁字母;因为域名的TLS最短是2位(如.au,
.us),最长可为4位(如.info, .asia);
右侧边界同样重要,否则我们之前的{2,4}就白费了;
使用i表示不分大小写;这是域名的特征之一。
回到本题
按照要求,一步步建立这条正则式。该正则式匹配的是
<item>...</item>结构。因此,正则式以
<item>开始。
在
<item>和
</item>之间不得出现color,是这条正则式的难点。因为,
color可能位于这个结构之内的任意一点,因此要规定,此内任意一点都不得出现color一词。这样的点为:
(?!color).。这样的点重复1+次,正则式写为
((?!color).)+。注意这里有个小陷阱:不要写为
(?!color).+,否则它只描述了最左侧的一点不得出现color,其余部分则都无所谓。而写为
((?!color).)+则保证每一点都不出现color。
正则式此时为
<item>((?!color).)+?</item>。为了节省资源,括号通常写成非捕获模式
(?:...);为了保证点号匹配换行符,可以指定s模式或使用
[\s\S]代替点号元字符。此处仍使用点号。正则式修改为
<item>(?:(?!color).)+?</item>。
总体来说,环视相对于基本的元字符还是要抽象一些。不过一旦理解并掌握了它,就会发现它在精确匹配和替换时十分有用。上面的分析,希望有所帮助。如果您有类似的问题,欢迎提出。
Tags: exclude,
lookaround,
negate, perl
原文来自:http://iregex.org/blog/negate-match.html
相关文章推荐
- 正则匹配密码只能是数字和字母组合字符串功能【php与js实现】
- 如何利用PHP来截取一段中文字符串而不出现乱码
- 请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。
- php中utf-8、gbk编码下用正则表达式如何匹配汉字[转]
- PHP 正则表达式如何匹配img中任意属性
- PHP正则表达式匹配自定义开头结尾之前字符串
- PHP 正则表达式,反向引用(获取匹配的字符串内容)
- PHP中preg_match函数正则匹配的字符串长度问题
- php小功能定制:对txt文本里面的字符串用正则表达式匹配
- PHP和javascript中使用正则表达式匹配中文字符串
- php正则匹配以“abc”开头且不能以“xyz”结尾的字符串
- java正则表达式匹配字符串字母,数字,空格和其他字符出现次数
- 辛星浅析php正则匹配中的utf字符串
- php中的正则函数:正则匹配,正则替换,正则分割 所有的操作都不会影响原来的字符串.
- php中utf-8编码下用正则表达式如何匹配汉字
- php正则表达式如何找到匹配模式中的最后一组
- 请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配
- php中utf-8编码下用正则表达式如何匹配汉字
- php面试题:如何知道一个未知长度的字符串哪个字符出现的次数最多?(字符串可由字母,数字及其他字符组成)请写出代码。
- php中utf-8编码下用正则表达式如何匹配汉字