2016-12-13 80 views
0

我理解只包含數字的正則表達式的過程,但是如何添加另一個條件使其不能包含某個子串。例如,匹配僅包含數字但不包含子字符串456的輸入的正則表達式。正則表達式匹配不包含其他模式的模式

鑑於此輸入(其中<empty>爲空字符串""):

0 
1456 
<empty> 
12345689 
1010101 
abc 

這些只有這些應該matche:

0 
<empty> 
1010101 

有人能解釋的正則表達式嗎?

+4

你的正則表達式是什麼? – user1211

+4

這可以很難做到。但你爲什麼想要?編寫「正常」代碼來進行檢查要容易得多。 – slim

+0

我準備進行測試,這是前幾年測試的問題。明確聲明必須寫在正則表達式 – unity1989

回答

2

您可以使用負先行使用這個表達式:

^(?![0-9]*456)[0-9]*$ 

RegEx Demo

  • (?![0-9a-zA-Z]*456)爲負先行的詞來禁止456
+0

不應該匹配字母或符號 – unity1989

+0

您是否檢查我的更新答案。 – anubhava

+0

與@波希米亞的答案一樣,這是低效的,因爲它遍歷整個輸入兩次。 – slim

1

使用負先行停泊開始,並匹配 「數字」:

^(?!.*456)\p{N}*$ 
+0

效率低下,因爲它會遍歷整個輸入兩次(雖然這很好,如果你知道輸入總是很小) – slim

2

我認爲這是你在找什麼:

public static void main(String[] args) { 
    String regex = "^((?!456)\\d)*$"; 
    String test = "123"; 
    String test2 = "456"; 
    String test3 = "asdf123"; 
    String test4 = "test456asdf"; 

    System.out.println(test.matches(regex)); // True 
    System.out.println(test2.matches(regex)); // False 
    System.out.println(test3.matches(regex)); // False 
    System.out.println(test4.matches(regex)); // False 
} 

即:

  • 字符串開頭
  • 零次或多次
    • 看看從這裏開始,這三個字符,如果是「456」
    • 匹配一個數字串
  • 結束不匹配

這裏有一個鏈接到fiddle,您可以在其中測試epsilon角色。

+0

但test3應*不*匹配:*只包含數字*。你的代碼甚至不通過OP的例子。 – Bohemian

+0

epsilon的字符不是一個數字,但OP要求返回?如果是這種情況,那麼只需替換'。'。 '\\ d' –

+0

我將'.'改爲'\ d',因此它只匹配數字。這使得它成爲正確的答案,如果我們允許自己的負面預測(這是Perl Monks青睞的解決方案 - http://www.perlmonks.org/?node_id=518444)。我無法編輯小提琴。 – slim

0

我認爲這個方法沒有任何「花哨」的正則表達式特徵,比如負向視圖。

^([0-35-9]*|4[0-46-9]|45[0-57-9]|4$|45$)*$ 

即:

  • 開始
    • 任何數量的:
      • 的數字序列不包括4
      • 或2炭號碼開頭「4 「,但不是」45「
      • 或開始與 「45」 3字符數,而不是 「456」
      • 或4-隨後結束
      • 或45,隨後結束

這符合正則表達式作爲有限狀態機的屬性。我們明確地處理了三個州 - (「未見過4」,「看過4」,「看過45次」)。如果我們希望我們的「不匹配」字符串是「4567」,我們必須明確添加另一個狀態,使模式更長,狀態機更大。

這是否符合您的需求取決於測試的目的 - 熟悉Java的正則表達式的高級特性,或者普遍應用正則表達式的能力(例如基本的grep,bash)。

消極的lookaheads,讓你表達更簡潔。

^((!?456)\d)*$ 

即(與它周圍的開始和結束錨),零個或多個重複單字符圖案的:(!?456)\d這意味着「沒有的456(向前看而不實際消耗)開始和相匹配的數字字符。」

要處理這個問題,正則表達式引擎只需要在當前字符前面查看3個字符,這是滿足要求的一種有效的單向方法。