2011-04-18 64 views
4
if(preg_match("/" . $filter . "/i", $node)) { 
    echo $node; 
} 

此代码过滤变量以决定是否显示它。 $ filter的示例条目将是“office”或“164(。*)976”。PHP反向Preg_match

我想知道是否有一种简单的方式来说:如果$ filter在$ node中不匹配。以正则表达式的形式?

所以......不是 “如果(!的preg_match” 但更多的是$过滤器= “!办公室” 或 “!164(。*)976”,而是一个工作的?

+3

你能说*为什么*你不想使用'!preg_match()'? – 2011-04-18 14:14:26

回答

10

这是可以做到如果你一定要使用“负正则表达式”,而不是简单地转换正正则表达式的结果:

if(preg_match("/^(?:(?!" . $filter . ").)*$/i", $node)) { 
    echo $node; 
} 

将匹配的字符串,如果它不包含$filter正则表达式/子

说明:(以office作为我们的例子字符串)

^   # Anchor the match at the start of the string 
(?:  # Try to match the following: 
(?!  # (unless it's possible to match 
    office # the text "office" at this point) 
)   # (end of negative lookahead), 
.   # Any character 
)*   # zero or more times 
$   # until the end of the string 
+0

我很好奇,你有什么想法,这会和'!preg_match()'方法相反吗?我不在一个可以测试它们的地方。 – 2011-04-19 21:53:06

+0

我期望这个解决方案的总体速度比否定方法慢,因为增加了查找断言的开销。实际结果将取决于您的输入是否通常匹配'$ filter'(在这种情况下否定会更快)或者它不会(在这种情况下,这种方法可能会更快)。 – 2011-04-20 06:04:28

6

(?!...)negative assertion是你在找什么。

要在主题中出现的任何地方,你可以使用这个双断言方法排除某些字符串:

preg_match('/(?=^((?!not_this).)+$) (......)/xs', $string); 

它允许还是指定任意的(......)主正则表达式。但是如果你只想禁止一个字符串的话,你可以不要这样做。

+0

非常感谢你的负面断言链接,这确实解决了我的问题,标记的答案也很好,但我很喜欢页面内的详细信息。 thx到目前为止。 – prdatur 2012-09-04 21:12:42

0

回答数2马里奥是正确的答案,这是为什么:

首先回答由贾斯汀·摩根的评论,

我很好奇,你有什么想法是什么这样做的性能将会与preg_match()方法相反,这与 相反?我不是在一个地方 我可以测试他们两个。 - 贾斯廷摩根4月19 '11在21:53

考虑门的逻辑片刻。

何时否定preg_match():查找匹配项时,如果缺少所需的正则表达式,或者希望条件为1),则为true;如果存在正则表达式,则为false。

当使用负断言的正则表达式:寻找匹配时,你想如果字符串正则表达式只匹配条件是真实的,如果有什么别的发现失败。如果您确实需要测试不希望的字符,同时允许忽略允许的字符,则这是必需的。

否定(的preg_match()=== 1)的结果只有当正则表达式是本测试。如果“酒吧”是必需的,数字不准,以下将不起作用:

if (preg_match('bar', 'foo2bar') === 1) { 
    echo "found 'bar'"; // but a number is here, so fail. 
} 

if (!pregmatch('[0-9]', 'foobar') === 1) { 
    echo "no numbers found"; // but didn't test for 'bar', so fail. 
} 

所以,要想真正测试多个正则表达式,一个初学者将测试使用多的preg_match()调用..我们知道这是一种非常业余的方式。

因此,作品想要测试可能的正则表达式的字符串,但条件可能只会传递为true,如果字符串至少包含其中之一。对于大多数简单的情况,简单地否定preg_match()就足够了,但对于更复杂或更广泛的正则表达式模式,它不会。我将使用我的情况来获得更真实的场景:

假设您想为某人的姓名(尤其是姓氏)创建用户表单。您希望系统接受所有字母,而不考虑大小写和放置位置,接受连字符,接受撇号并排除所有其他字符。我们知道,为所有不需要的字符匹配一个正则表达式是我们首先想到的,但想象一下,您正在支持UTF-8 ......这是很多人物!你的程序几乎和UTF-8表一样大!我不在乎你有什么硬件,你的服务器应用程序对命令的长度有限制,更不用说限制200个括号内的子模式,所以ENTIRE UTF-8字符表(减去[AZ],[az ], - 和')太长,不要介意程序本身会很大!因为我们不会使用一个if(!preg_match('。#\\ $ \%... ...'这可能是相当长的并且不可能评估...在字符串上以查看字符串是否不好,我们应该将测试更简单的方法,对正则表达式的断言否定环视,然后用否定的整体结果:

<?php 
    $string = "O'Reilly-Finlay"; 
    if (preg_match('/?![a-z\'-]/i', $string) === 0) { 
    echo "the given string matched exclusively for regex pattern"; 
    // should not work on error, since preg_match returns false, which is not an int (we tested for identity, not equality) 
    } else { 
    echo "the given string did not match exclusively to the regex pattern"; 
    } 
?> 

如果我们只找了正则表达式[AZ \' - ]/I,所有我们说是“匹配字符串,如果它包含任何这些东西”,那么不好的字符就不会被测试,如果我们否定了这个函数,我们会说“如果找到包含任何这些东西的匹配,就返回false”。因此我们需要说“如果我们在正则表达式中匹配任何东西,则返回false”,这是用lookahead来完成的。钟声在某人的脑海中熄灭,他们正在思考通配符的扩展风格......不,前瞻不会这样做,它只是对每场比赛都进行否定,然后继续。因此,它会检查正则表达式的第一个字符,如果它匹配,它将继续前进直到找到不匹配或结束。完成之后,发现与正则表达式不匹配的所有内容都会返回到匹配数组,或者简单地返回1.简而言之,在正则表达式'a'上声明为负值与匹配正则表达式'b'相反,其中'b'包含一切都不能与'a'匹配。当'b'不合时宜时,这很有用。

注意:如果我的正则表达式有错误,我很抱歉...我在过去几个月一直在使用Lua,所以我可能会混合我的正则表达式规则。否则,'?!'是适合PHP的lookahead语法。