我們可以嘗試一種不同的方式。你所做的嘗試允許一些字符串滑過你不想要的。也就是說,一切都有重複。在下面,我將用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
根據您的語言 - 只要它使那些東西方便性和可讀性。
這是什麼語言? – Jaanus
Jaanus:這應該是無關的幾乎所有回答這個問題,除非您使用的是非常簡單的實現還是一個從上世紀70年代左右。 – Joey
僅供參考,我已經添加了'ITP',請刪除它是否應該在那裏。 –