您现在的地位: 365体育备用网址 > 365学习 > 正则不包含某些字符串的表示式匹配方法

正则不包含某些字符串的表示式匹配方法_365体育备用网址官网资讯

您现在的地位: 365体育备用网址 > 365学习 > 正则不包含某些字符串的表示式匹配方法

正则不包含某些字符串的表示式匹配方法

文章来源:365jz.com     点击数:90    更新时间:2017-12-24 11:19   参与评论

经常我们会遇到正则不包含某些字符串的文本,^(hede)来过滤”hede”字串,但这种写法是失误的。我们能够这样写:[^hede],但这样的正则表示式完全是另外一个意义,它的意义是字符串里不能包含‘h',‘e',‘d'三个但字符。那什么样的正则表示式能过滤出不包含完整“hello”字串的信息呢?

事实上,说正则表示式里不撑腰逆向匹配并不是百分之百的正确。就像这个问题,我们就能够使用否定式查找来模拟出逆向匹配,从而解决我们的问题:

^((?!hede).)*$

上面这个表示式就能过滤出不包含‘hede'字串的信息。我上面也说了,这种写法并不是正则表示式“擅长”的用法,但它是能够这样用的。

 

解释

一个字符串是由n个字符组成的。在每个字符之前和之后,都有一个空字符。这样,一个由n个字符组成的字符串就有n+1个空字符串。我们来看一下“ABhedeCD”这个字符串:

一切的e编号的地位都是空字符。表示式(?!hede).会往前查找,看看前面是不是没有“hede”字串,如果没有(是其它字符),那么.(点号)就会匹配这些其它字符。这种正则表示式的“查找”也叫做“zero-width-assertions”(零宽度断言),因为它不会捕获任何的字符,只是推断。

在上面的例子里,每个空字符都会检讨其前面的字符串是否不是‘hede',如果不是,这.(点号)就是匹配捕捉这个字符。表示式(?!hede).只执行一次,所以,我们将这个表示式用括号包裹成组(group),然后用*(星号)修饰——匹配0次或多次:

((?!hede).)*。

你能够了解,正则表示式((?!hede).)*匹配字符串"ABhedeCD"的结果false,因为在e3地位,(?!hede)匹配不合格,它之前有"hede"字符串,也就是包含了指定的字符串。

 

在正则表示式里, ?! 是否定式向前查找,它帮我们解决了字符串“不包含”匹配的问题。

以下是一些补充:

找出一切img标签的,没有带说明属性alt的标签: 

正则:<img(?![^<>]*?alt[^<>]*?>).*?> 
例子:<img src="" alt=""> <img src="" >  <img src="" title="">  <img src="" id="">  <img src=""  title="" alt=""> 

扩展,如果要找没有带title属性的a应该是: 

正则:<a(?![^<>]*?title[^<>]*?>).*?> 
例子:<a src="" alt=""> <a src="" >  <a src="" title="">  <a src="" id="">  <a src=""  title="" alt=""> 

PHP正则提取不包含指定网址的海王星真人网上娱乐地址的例子:
 

$contents = '<p>疲乏是一种享受,让我们无暇空虚;崎岖是一种经历,让我们真切的了解人生;
            忙碌是一种幸福,让我们没有时间体验痛苦;奔波是一种快乐,
    <img src="http://img.baidu.com/hi/ldw/w_0009.gif" />
    <img src="http://img.baidu.com/hi/jx2/j_0020.gif" />
    <img src="http://img.baidu.com/hi/jx2/j_0042.gif" />
    <img src="http://img.baidu.com/hi/jx2/j_0015.gif" />
    <img src="/uploads/image/20140420/13979336569926.jpg" />
    <img src="/13979336569926.jpg" />';

preg_match('#<img src="(?!http:\/\/img.baidu)([^"]+)"#', $contents,$matches);

var_dump($matches);

//运行结果

/*
array (size=2)
  0 => string '<img src="/uploads/image/20140420/13979336569926.jpg"' (length=77)
  1 => string '/uploads/image/20140420/13979336569926.jpg' (length=66)

*/



查找不以baidu开头的字符串

baidu.com
sina.com.cn

正则:^(?!baidu).*$  匹配结果就是第2行,也就是第1行被排除了
这里使用了零宽度断言(?!exp),注意,我们有一个向前查找的语法(也叫顺序环视)  (?=exp)
(?=exp) 会查找exp之前的【地位】如果将等号换成感叹号,就变成了否定语义,也就是说查找的地位的后面不能是exp
一般情况下?!要与特定的锚点相结合,例如^行开头或者$行结尾,那么上面的例子的意义如下:
^(?!baidu).*$ 先匹配一个行开头的地位,并且要求接下来的地位的后面不是baidu这个字符串。这样由于第一行^之后的地位后面是baidu所以匹配失败,被排除在外了。


查找不以com结尾的字符串

www.sina.com.cn
www.educ.org
www.hao.cc
www.baidu.com
www.123.com

正则 ^.*?(?<!com)$  匹配前3行结果。
如果查找以com结尾的字符串则使用正则 ^.*?(?<=com)$或者 ^.*?com$ 
对正则表示式的解释:^.*?(?<!com)$
首先匹配行开头,然后是 .*? 这个是疏忽优先,也就是优先疏忽不匹配任何字符,(?<!com) 这个是一个逆序环视的否定形式,意义是匹配一个地位此地位的前面不能是字符串com,最后是一个行结束。对于www.123.com来说,首先匹配行首,接着匹配w后面的地位,发现前面不是com,所以胜利但紧接着要匹配行尾,失败,回溯让.*? 匹配一个w符号,接着(?<com)匹配第二个w后面的地位,发现前面也不是com匹配胜利,紧接着要匹配$对应的行尾失败,一直到.*?匹配了www.baidu.com的时刻,此时(?<!com)匹配m后面的地位,此时此地位的前面是com匹配直接失败,接着.*?匹配行末尾,(?<!com)匹配$后面的地位,显然这次也失败了,所以整个全局匹配都失败。  www.123.com被排除到匹配之外。这里的.*后面加不加问号结果都一样。


查找不含有if的行

if (a>b)
printf("hello");
else if(a<b)
printf("hello2");
else
printf("hello3");

正则 ^([^f]|[^i]f)+$
其实这个匹配也是一个排除型字符串的匹配,但是不同于上面两种,因为这里的if可能既不在行开头,也不在行结尾,而是在字符串中间这样就给匹配带来了麻烦,在正则表示式中没有提供类似排除的功能。我们最容易想到的就是下面的正则:
^[^if]+$ 这种写法看起来是那么回事,但是排除型字符组排除的是i和f两个字符,而不是if这个字符串,所以这个正则表示式匹配的是那些既没有i字符也不包含f字符的字符串。但是如果字符串中有一个i或多个i或者有一个或多个f,或者i和f字符都有只不过没有连在一起。这些情况都是我们需要匹配的情况,而我们不能匹配的情况是那些包含if字符串的行,而不是包含i或f字符的行,所以这种写法漏洞很大。

^.*(?!if).*$ 这种写法使用了零宽度断言,表面意义看起来仿佛是说 任意字符+非if+任意字符 组成了整个字符串,但是细致研究匹配进程就知道这个是错的,(?if)匹配的是一个地位,所以对于字符串aifb他也是能够匹配到的,而实际上这样的字符正是我们不要的。按照这个正则表示式,对于aifb 首先匹配行首,其次.*是贪欲模式(匹配优先),会一直匹配到字符串的末尾(此时传动装置定位在$地位前面),此时(?!if)需要匹配一个地位,这个地位的后面不能是if,这个时刻正好地位在b字符的后面,符合匹配条件,紧接着匹配行尾,到这里整个全局匹配胜利。

也就是说对于一个字符串例如我要排除abc这个字串,那么对于任意一个字符串   helloworld abc helloworld 在匹配的时刻(?!abc)能够匹配h、e、l、l、o、w、o、r、l、d等这些字符后面的地位,都是胜利的。所以匹配基本还没有进行到abc这个地方,(?!abc)就会匹配胜利。这个时刻基本起不到排除的作用,365体育备用网址上面的第1和第2个例子能够呢,因为他们的地位有行首和行尾限定。例如我要匹配行首不是abc的话,那么此时^(?!abc) 这个时刻(?!abc)实际上在匹配的时刻其传动装置的地位被行首进行了限定,所以对于那些以abc开头的字符串来说就会匹配失败了。

对于正则表示式^.*(?!abc).*$怎么能让第一个.*匹配到 helloworldabcxxx中的helloworld的问题。

对于上面的题目,我们的答案是^([^f]|[^i]f)+$  其实就将一切的匹配分成了2种情况,一种情况是假设字符串中没有f字符,    自然就不可能有if字符串了,这种情况下匹配的字符串中是不可能有if的。第二种情况就是有f字符,但是我们要求此时f的前面不能是i,所以在有f和没有f两种情况都考虑到的情况下,这个正则就应该能够满足一切的情况了。

其实这个问题的解答是不完善的,对于排除的字符串if只有2个字符i和f字符,我们能够使用这种方式,但是如果我们要排除的是字符串helloworld,这种方法显然就不有用了,那要考虑到多少种情况呢?

排除不含有某字符串的最终方案:在这种情况下我们使用  ^(?!.*helloworld).*$  正则表示式  我们将第一个.*移到了零宽度断言的里面。在匹配的时刻首先匹配行首的地位,然后接下来是匹配行首后面的地位,要求此地位的后面不能是    .*helloworld 匹配的字符串,说白了要求此地位的后面不能是xxxxxxxxxxxxxxxxxxhelloworld 类似的字符串,这样就排除了从行首开头后面含有helloworld的情况了。

 在使用正则表示式的场合,往往有这种需求,就是匹配一个不包含某个子串的子符串。比如说,我要从“eabcdfgh”得到"cd"之前的子串。有些人可能会写:
([^cd]*)
这种写法是彻底失误的,因为[]中的是集合,也就是说,[^cd]表示不等于c或者d,而不是cd。下面的程序中没有cd,但eab还是被匹配出来了。

String s = "([^cd]*)";
Match m = Regex.Match("eabcfgh", s);
MessageBox.Show(m.Value);//eab
MessageBox.Show(m.Groups[1].Value);//eab

上面这种写法是错的比较离谱的,正常青年一般都能够幸免这种失误。在特别情况下,正则表示式能够这么写,而且效率是比较高的。
([/s/S]*cd)
先说明下/s/S是表示匹配任何字符。所谓特别情况,就是我知道这个字符串中必有cd的存在。假如,我的要求是匹配不包含cd的部分(为了描述方便,只匹配cd之前的部分),也就是说,当cd不存在时,应该把整个字符串都取出来。

String s = "((.(?!cd))*.)";
//String s = "([/s/S]*cd)";
Match m = Regex.Match("eabcdfgh", s);
MessageBox.Show(m.Value);//eab
MessageBox.Show(m.Groups[1].Value);//eab

这种写法终于符合要求了。不过值得一提的是,相较前一种而言,它的效率比较低。
回忆一下相关的语法:
(?:子表示式)         定义非捕获组。
//定义非捕获组

String s = "e(?:ab)(.*)";
Match m = Regex.Match("eabcd", s);
MessageBox.Show(m.Value);//eabcd
MessageBox.Show(m.Groups[1].Value);//cd

ab是被匹配的,但是它所在的组没有被捕获,Group[1]是cd
(?=子表示式)       零宽度正预测先行断言。
//零宽度正预测先行断言

//String s = "b(cd|de)(.*)";
String s = "b(?=cd|de)(.*)";
Match m = Regex.Match("eabcdfg", s);
MessageBox.Show(m.Value);
MessageBox.Show(m.Groups[1].Value);//区别 cd  cdfg

这种写法和注释掉的写法是有区别的,区别就是“零宽度”,这种写法会被捕获,也就是不占一个Group。
(?!子表示式)       零宽度负预测先行断言。
!表示非,就是不包含,同样是零宽度,不会被捕获。

(?<=子表示式)    零宽度正回忆后发断言。
例:(?<=19)\d{2}\b
“1851 1999 1950 1905 2003”中的“99”、“50”和“05”
(?<!子表示式)     零宽度负回忆后发断言。
例:(?<!19)\d{2}\b
“1851 1999 1950 1905 2003”中的“51”和“03”
 

如对本文有疑问,请提交到交流龙都国际,广大热心网友会为你解答!! 点击进入龙都国际


公布评论 (90人察看0条评论)
请自觉遵守互联网相关的政策法规,严禁公布色情、暴力、反动的言论。
用户名: 验证码: 点击我更换海王星真人网上娱乐
最新评论
------分隔线----------------------------
条评论
Sitemap