2011-09-08 149 views
4

我有以下的正則表達式:簡化正則表達式?

(?i:^TPI$|^TIP$|^IPT$|^ITP$|^PIT$|^PTI$|^IP$|^PI$|^TI$|^IT$|^PT$|^TP$|^T$|^P$|^I$) 

我怎麼能簡化呢?我的正則表達知識是相當有限的。

我的要求是:

  • 可接受輸入爲 「T」, 「P」 和 「I」
  • 值可能會在任何順序
  • 接受每個值只有一個。 「TTI」 是無效的,但 「TI」 是有效的
  • 不區分大小寫

我在過去使用

^(?i:[TPI]){1,3}$ 

,而且大多是工作。唯一的問題是它接受多個值「TTT」對於那個正則表達式是可以接受的,我需要這個失敗)。

+0

這是什麼語言? – Jaanus

+1

Jaanus:這應該是無關的幾乎所有回答這個問題,除非您使用的是非常簡單的實現還是一個從上世紀70年代左右。 – Joey

+0

僅供參考,我已經添加了'ITP',請刪除它是否應該在那裏。 –

回答

6

我們可以嘗試一種不同的方式。你所做的嘗試允許一些字符串滑過你不想要的。也就是說,一切都有重複。在下面,我將用PowerShell做一些實驗來展示解決方案。首先,我們需要所有可能的字符串,我們可以期待作爲輸入:

$tests = 'TPI'[0..2]|%{$a=$_;"$a"; 'TPI'[0..2]|%{$b=$_;"$a$b"; 'TPI'[0..2]|%{"$a$b$_"}}} | sort 

這將產生以下值的序列(I格式化他們在同一行,但他們出來每行一個通常情況下):

$tests 
I II III IIP IIT IP IPI IPP IPT IT ITI ITP ITT P PI PII PIP PIT PP PPI PPP PPT PT PTI PTP PTT T TI TII TIP TIT TP TPI TPP TPT TT TTI TTP TTT 

這當然亦是正則表達式

^(?i:[TPI]){1,3}$ 

將匹配。

我們可以限制我們想要通過使用所謂的負先行斷言,以匹配其將匹配只有一些文字是以下,但不會實際匹配的文本本身,從而允許其被捕獲你有上面的模式。這可以通過(?!)完成,您可以在!之後插入一些子表達式。讓我們嘗試並限制輸入不帶有兩個I,二P或兩個T開始:

$tests -match '^(?!II|PP|TT)(?i:[TPI]{1,3})$' 
I IP IPI IPP IPT IT ITI ITP ITT P PI PII PIP PIT PT PTI PTP PTT T TI TII TIP TIT TP TPI TPP TPT 

正如你可以看到,那些從結果了。如果我們使用捕獲組和反向引用,我們可以簡化它。通常小括號(除非以(?開頭)捕獲它們內部匹配的內容,並且可以在匹配後使用它來從匹配或替換中提取部分。但你也可以在模式中使用它本身在很多正則表達式引擎中(實際上,我認爲沒有引擎允許負向預測,但而不是模式中的反向引用)。所以II|PP|TT可以寫成(.)\1,它只是說「一封信,後面是完全相同的字母」,因爲\1是反向引用,指向與(.)匹配的任何內容。

現在我們仍然有我們不希望幾個值,即一切有兩個相同的字母在位置2和3的位置1和3,我們可以擺脫前者的有以下:

$tests -match '^(?!.?(.)\1)(?i:[TPI]{1,3})$' 
I IP IPI IPT IT ITI ITP P PI PIP PIT PT PTI PTP T TI TIP TIT TP TPI TPT 

中的.?現在開始說「相匹配的字符或沒有」的延伸,因此我們有什麼前兩排除比賽用到底重複。對於第二組,我們只需要排除的樣子(.).\1匹配,即一個字母,緊接着又和隨後的第一個重複。我們可以只把另一.?,捕獲組和反向引用之間,即一個可選的信延長上述正則表達式:

$tests -match '^(?!.?(.).?\1)(?i:[TPI]{1,3})$' 
I IP IPT IT ITP P PI PIT PT PTI T TI TIP TP TPI 

現在正是你想要表示該集合。最終的正則表達式是

^(?!.?(.).?\1)(?i:[TPI]{1,3})$ 

它比以前更短,這是肯定的。是否更簡單可能需要辯論,因爲它可能需要一些解釋。對於另一個答案中更加壓縮的方法,情況更是如此。它確實短一些,但這就是我的答案,我們爭奪選票,我只能說我不喜歡它;-) ...只是在開玩笑。但對於這樣的事情,我想將基本模式與排除規則分開確實對於可讀性有意義。

另一種選擇可能是驗證基本模式與正則表達式,即您的初始方法。然後使用代碼來拒絕重複這可能看起來像

($s.ToLowerInvariant().ToCharArray() | select -Unique).Count -eq $s.Length 

根據您的語言 - 只要它使那些東西方便性和可讀性。

+1

我認爲你已經有了你的60k – sidyll

+0

還沒有,而且這個問題的流量非常低---) – Joey

+0

不應該,這個問題真的很好,你想出的答案只是真棒。如果它是固定長度(3),我已經回答'/(?: T()| P()| I()){3} \ 1 \ 2 \ 3 /'但你是更簡單的用於這樣的任務。 – sidyll

1

這裏是爲子孫後代着想另一個答案。

^(?i:([TPI])(?!.*?\1)){1,3}$