2011-04-18 62 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語法。