2012-06-21 176 views
14
之間

例如與五個字母ABCDE一個字,每個字母出現正好一次,以任意順序,沒有休息,字崩潰會因爲debac工作,但海底將不起作用,因爲:1.在任何可以形成的5個字符的序列中沒有c,並且2.字母e出現兩次。又如,反饋將因爲edbac而工作。請記住,解決方案必須僅使用正則表達式來完成。使用正則表達式來查找

我試圖實施的策略是:匹配第一個字母,如果它在[a-e]裏面,並記住它。然後找到[a-e]中的下一個字母,但不是第一個字母。等等。我不知道語法是什麼(或者即使某些語法存在的),所以我的代碼沒有工作:

open(DICT, "dictionary.txt"); 
@words = <DICT>; 

foreach my $word(@words){ 

if ($word =~ /([a-e])([a-e^\1])([a-e^\1^\2])([a-e^\1^\2^\3])([a-e^\1^\2^\3^\4])/ 
){ 
    print $word; 
} 
} 

我也在想使用(=正則表達式?)和\ G變的,但我沒」確定它會如何工作。

回答

15
/ 
    (?= .{0,4}a) 
    (?= .{0,4}b) 
    (?= .{0,4}c) 
    (?= .{0,4}d) 
    (?= .{0,4}e) 
/xs 

這可能導致更快的匹配,生成所有組合的模式。

use Algorithm::Loops qw(NextPermute); 
my @pats; 
my @chars = 'a'..'e'; 
do { push @pats, quotemeta join '', @chars; } while NextPermute(@chars); 
my $re = join '|', @pats; 

ABCDE | abced | abdce | ABDEC | ABECD | abedc | acbde | acbed | acdbe | acdeb | acebd | acedb | adbce | adbec | adcbe | adceb | adebc | adecb | aebcd | aebdc | aecbd | aecdb | aedbc | aedcb | bacde | baced | badce | badec | baecd | baedc | bcade | bcaed | bcdae | BCDEA | bcead | bceda | bdace | bdaec | bdcae | bdcea | bdeac | bdeca | beacd | beadc | becad | becda | bedac | bedca | cabde | cabed | cadbe | cadeb | caebd | caedb | cbade | cbaed | cbdae | cbdea | cbead | cbeda | cdabe | cdaeb | cdbae | cdbea | cdeab | cdeba | ceabd | ceadb | cebad | cebda |中央評價數據庫| cedba | dabce | dabec | dacbe | daceb | daebc | daecb | dbace | dbaec | dbcae | dbcea | dbeac | dbeca | dcabe | dcaeb | dcbae | dcbea | dceab | dceba | DEABC | deacb | debac | debca | decab | decba | EABCD | eabdc | eacbd | eacdb | eadbc | eadcb | ebacd | ebadc | ebcad | ebcda | ebdac | ebdca | ecabd | ecadb | ecbad | ecbda | ecdab | ecdba | edabc | edacb | edbac | edbca | edcab | edcba

(這將在Perl 5.10+中得到優化。 5.10之前,使用正則表達式::列表。)

+1

+1 - 我比我自己的解決方案更喜歡這個。爲了向其他人解釋,這些預測保證:在接下來的5個字母中,至少有一個'a',至少一個'b',至少一個'c',至少一個'd'和至少一個' E」。鑑於只有五個「插槽」,它保證每個只出現一次。 –

+0

增加了替代解決方案。 – ikegami

+0

如果你想找到重複的東西(例如abcdd而不是abcde) – ikegami

6
#! perl -lw 
for (qw(debacle seabed feedback)) { 
    print if /([a-e])(?!\1) 
     ([a-e])(?!\1)(?!\2) 
     ([a-e])(?!\1)(?!\2)(?!\3) 
     ([a-e])(?!\1)(?!\2)(?!\3)(?!\4) 
     ([a-e])/x; 
} 
7

你的解決方案是聰明,但遺憾的是[a-e^...]不起作用,因爲你發現了。我不相信有一種方法可以混合規則和否定字符類。我能想到用向前看符號雖然一種解決方法:

/(([a-e])(?!\2)([a-e])(?!\2)(?!\3)([a-e])(?!\2)(?!\3)(?!\4])([a-e])(?!\2)(?!\3)(?!\4])(?!\5)([a-e]))/ 

見這裏:http://rubular.com/r/6pFrJe78b6

UPDATE:暴徒在下面的評論中指出,該交替可以用來壓縮以上:

/(([a-e])(?!\2)([a-e])(?!\2|\3)([a-e])(?!\2|\3|\4])([a-e])(?!\2|\3|\4|\5)([a-e]))/ 

新的演示:http://rubular.com/r/UUS7mrz6Ze

+0

請注意,你不能在字符類中有反向引用。因此需要多個反向引用而不是像''(?![\ 2 \ 3 \ 4 \ 5])''。此外,我不得不從2開始計數,因爲我想爲rubular演示包含一個「整體」捕獲組。 –

+1

但你可以使用替代:'...(?!\ 2 | \ 3 | \ 4 | \ 5)' – mob