2014-09-05 21 views
3

我有這樣一串字符:ABBCD正則表達式匹配的一組有限的字符組成的字符串不重用任何字符

而且我有幾個空格這樣的:_ _ _

有沒有一種方法可以使用正則表達式來匹配任何可以通過將可用字符「拖動」到空格中而形成的字符串?

因此在本例中,這些都是一些有效的匹配:

A B C 
A B B 
B C B 
D A B 

但這些都無效:

A A B // Only one 'A' is available in the set 
B B B // Only two 'B's are available in the set 

很抱歉,如果它已經被問過。

+5

我不認爲正則表達式是一個很好的工具。你應該特別研究'Collections',Set's。我認爲你的問題太廣泛了。我建議你嘗試一些代碼,並重新制定一個具體問題。 – Mena 2014-09-05 10:30:53

+0

那麼我已經有了一個純代碼解決方案。但我只是想知道這是否可以用RegExp完成,這會給我更多的靈活性。但是,當然,我瞭解RegExp是否無法做到這一點。 – CluelessNoob 2014-09-05 10:33:11

回答

8

vks's solution would work properly,這裏是它增加了優化,以滿足「_ _ _」規則:

^(?!(?:[^A]*A){2})(?!(?:[^B]*B){3})(?!(?:[^C]*C){2})(?!(?:[^D]*D){2})(?:[ABCD](?:\s|$)){3} 

Here is a regex demo。從原來的正則表達式

變化:

  • 捕獲組被刪除,因爲我們是在Java中 - Java的正則表達式實現獻給時間匹配時寫捕獲組)。
  • 定位器^在前面移動以便讀取正則表達式。

正則表達式的解釋:

  • ^在比賽開始斷言位置。
  • (?!負前瞻 - 斷言我們的立場不會以下匹配,而無需移動鼠標指針:
  •     (?:[^A]*A){2}兩個「A」 S(文字字符),與非「A」以最佳方式滾動。
  • )關閉組。
  • (?!(?:[^B]*B){3})與上面的組相同 - 斷言有不是三個「B」 s在比賽中。
  • (?!(?:[^C]*C){2})斷言有不是兩個「C」 s在比賽中。
  • (?!(?:[^D]*D){2})斷言有不是兩個「D」 s在比賽中。
  • (?:非捕獲組:匹配以下內容而不捕獲。
  •     [ABCD]從列表任何字符 「A」「B」「C」,或「d」
  •     (?:\s|$)一個空格或字符串的結尾。
  • ){3}三次 - 必須完全匹配序列三次才能滿足規則「_ _ _」規則。

要使用正則表達式:

boolean fulfillsRule(String str) { 
    Pattern tripleRule = Pattern.compile("^(?!(?:[^A]*A){2})(?!(?:[^B]*B){3})(?!(?:[^C]*C){2})(?!(?:[^D]*D){2})(?:[ABCD](?:\s|$)){3}"); 
    return tripleRule.matcher(str).find(); 
} 
+0

可以用空格結尾。有類似的,我可以從一個空間開始(編輯)。但不知道,如果這是一個要求。 – 2014-09-06 09:12:06

+1

@ Jonny5這是非常真實的!你可以將'(?:[ABCD](?:\ s | $)){3}'轉換爲'[ABCD] [ABCD] [ABCD]',但這很難看。 – Unihedron 2014-09-06 09:14:58

5
(?!(.*?A){2,})(?!(.*?B){3,})(?!((.*?C){2,}))(?!((.*?D){2,}))^[ABCD]*$ 

您可以使用類似這樣的東西。

http://regex101.com/r/uH3fV3/1

+0

+1。小調:這個正則表達式也會接受類似'ABCfoofoofoofoofoo'的東西,因爲'。*'接受所有字符,所以這可能會導致一些錯誤。您可以使用'[ABBCD] *',而不是'。*',它也可以優化爲[ABCD] *'(這裏不需要重複字符)。 – Pshemo 2014-09-05 11:02:02

+0

@Pshemo thanx很多的編輯。這使得這更安全:) – vks 2014-09-05 11:03:58

+0

如果你想改善你的答案,你可以添加這個正則表達式的工作原理的解釋。添加'^ [ABCD] * $'或者'(?!(。*?B){3,})',這裏有什麼目的。 – Pshemo 2014-09-05 11:11:43

2

有趣的問題,這是我的想法:

(?m)^(?!.*([ACD]).*\1)(?!(?>.*?B){3})(?>[A-D]){2}[A-D]$ 

使用(?m) MULTILINE modifier其中^比賽線路開始和$行結束。

Test at regexplanet(點擊Java); regex101(不支持Java)


如果我的理解是正確的,可用字符鍋A,B,B,C,D。一個字符串應該是有效的,如果它包含0或1的每個[ACD]0-2B在你的例子中。我的模式由3個部分組成:

  • (?!.*([ACD]).*\1)使用在線路開始^負前瞻,以確保,即[ACD]最多出現一次,通過捕捉[ACD]\1和檢查,沒有任何地方發生兩次吧。

  • (?!(?>.*?B){3})使用負先行,以保證,B發生至多2X

  • 終於(?>[A-D]){2}[A-D]$決定了總可用字符集,確保格式化,其中每個字母必須以空格或開始前綴,並檢查長度。

這可以很容易地修改爲其他需要。另見SO Regex FAQ

+1

偉大的方法!這解決了我和vks'不同思維的問題。雖然它聲稱完成並且失敗的速度快於成功,但這是匹配的一個小缺點。 – Unihedron 2014-09-05 13:44:22

+0

+1用於鏈接到正則表達式引用。我想指出''(?>)'組也可以修改爲'(?:)'。 – Unihedron 2014-09-05 13:45:22

+0

謝謝@Unihedron。我也喜歡你的和@vks的方法,並且喜歡那些「正則表達式」。)我的模式中的'B'部分可能會以更緊湊的方式用負面視圖來完成,類似於第一部分。 – 2014-09-05 13:48:24