嘗試使用正則表達式構建邏輯“與”運算時,我們有幾種方法可以遵循。 第一種方法似乎很明顯,但是如果考慮一下,默認情況下正則表達式是邏輯“和”的。 正則表達式中的每個順序字符都一起“與”。 如果您可以按順序表達您的陳述,那麼工作已經爲您完成。
但是,既然您已經搜索了這麼遠,我們可以假設您正在尋找更高級的東西。 爲方便起見,我們有兩個選擇:我們可以使用“ lookaheads”,或者如果您使用的任何工具或語言支持,也可以使用單獨的正則表達式執行第二次匹配。
先行查找實現邏輯“與”
先行查找和後向操作本質上是可以放在正則表達式上的額外約束。 您可以指定成功匹配需要滿足的其他模式。 以下是預讀表達式的示例。
(?=.*word1)(?=.*word2)(?=.*word3)
請注意,每個表達式都包含.*
–這是因爲先行查找對位置敏感,並且從它們在模式中出現的位置開始匹配; 因此,例如,如果我們有一個類似於以下模式的模式:
^Start (?=.*kind)(?=.*good)(?=.*word).* deed$
此模式將匹配"Start with a good word and end with a kind deed
" and “Start with a kind word and end with a good deed
”
總結:一旦開始第一個look-ahead
,就保存表達式中的匹配位置。 第一個look-ahead
中的.*
匹配獲得kind
之前需要的多個字符; 匹配位置被重置,並且下一個look-ahead
向前搜索“good
”; 最後但並非最不重要的一點是,我們最終的look-ahead
將搜索“word
”,然後像往常一樣恢復模式匹配。 匹配繼續使用表達式的基本.*
,並繼續通過“deed”匹配到字符串的末尾。
這樣做的原因是,如上所述,因爲在評估每次環視後都會重置匹配位置。 這意味着我們相鄰的“and”look-ahea
表達式的順序並不重要。 但是,如果我們將條件之一移至.*
之後,則會看到不同的結果:
^Start (?=.*kind).*(?=.*good) deed.$
現在(?=.*good)
排在我們的catch-all
之後,我們之前的字符串都不匹配,因爲在評估.*
之後不可能存在“good
”。
提示,如果要匹配整個單詞而不是較長單詞的部分字符串,則需要在語句中添加單詞邊界:
^Start (?=.*\bkind\b)(?=.*\bgood\b)(?=.*\bword\b).* deed$
用您的語言實現邏輯“與”
如果所有其他方法都失敗了,那麼您應該始終簡單地執行另一場比賽,並使用所選編程語言的本機“and”邏輯功能將結果組合在一起,您總是會感到自在。 對於其他人來說,將來通常更容易維護,並且對中等數據集的性能影響很小。 例如,在Java中:
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class RegexTest
{
@Test
public void testRegex()
{
assertTrue(stringMatches("Start with a good word and end with a kind deed."));
assertTrue(stringMatches("Start with a kind word and end with a good deed."));
assertFalse(stringMatches("Start with a deed."));
}
private boolean stringMatches(String string)
{
return string.matches("^Start .* deed.$") && string.matches(".*good.*") && string.matches(".*kind.*");
}
}