2013-04-18 90 views
2

N定義的話,這個問題3個字例如:openicebreakerumbrela首字母縮寫詞搜索正則表達式建設與perl

想知道這裏的任何可能的縮寫詞是什麼作爲英語單詞存在,例如,想運行是這樣的:在上述正則表達式,然後我決定

grep -Pi '^o(p(e?))?i(c(e?))?um?$' my_long_wordlist.txt 

我可以使用

  • 從第一個字o,或opope(第一或前兩個或前三個字母)
  • 從第2個字i,或icice(第一或前兩個或前三個字母)
  • ,最終形成的最後一個字我可以使用LY第一或firtst兩個字母 - uum

的樂趣 - 上述正則表達式將返回我的一句話:opium :)

用手構建的正則表達式是一個兩個測試可以接受的,但我想檢查很多單詞組合,所以,尋找如何生成正則表達式的方式如上。

要建立一個「的縮寫取景器的正則表達式腳本」與以下電話:

acrobuild open:4 icebreaker:3 umbrela:3 

正如你所看到的,在ARG遊戲的話,和分隔符後面的數字是最大數信從一開始就可以在首字母縮寫中使用什麼。

現在的問題 - 我完全失去了如何建立給定長度的正則表達式。需要一些提示,想法或想。 - 勾選「需要幫助這裏」 :)

目前我有這樣的:

#!/usr/bin/perl 

use 5.012; 
use strict; 
use warnings; 

do_grep( make_regex(@ARGV)); 
exit; 

sub make_regex { 
    my(@words) = @_; 
    my $regex; 
    foreach my $wordnum (@words) { 
     $regex .= make_word_regex(split(/:/, $wordnum)); 
    } 
    $regex = '^' . $regex . '$' if $regex; 
    return $regex; 
} 

sub make_word_regex { 
    my($word, $num) = @_; 

    return "" unless $word; 
    $num = length($word) unless defined($num); #for make legal -> word:0 

    my(@chars) = split(//, substr($word,0,$num)); 

    #regex building x or xy? or x(y(z?))? etc... :(
    my $re = ""; 
    foreach my $c (reverse(@chars)) { #reverse, to building inside-out 
     # HOW TO BUILD THE REGEX HERE? 
     # NEED HELP HERE 
    } 
    return($re); 
} 

sub do_grep { 
    my($re) = @_; 
    say "$re"; return; #tmp 
    my $recomp = qr/$re/i; 

    open(my $fdict, "<", "/usr/share/dict/web2") or die("No dict file $!"); 
    while(<$fdict>) { 
     chomp; 
     say $_ if m/$recomp/; 
    } 
    close($fdict); 
} 

回答

2

而非嵌套的正則表達式o(p(e?)?),我只想讓候補名單: (o|op|ope)

sub make_regex_word { 
    my ($word)[email protected]_; 
    my ($base,$count)=split(/:/,$word); 
    my @chars=split(//,$base); 
    my @re=(); 
    for ($i=0;$i<$count;$i++) { 
     push @re,join("",@chars[0..$i]); 
    } 
    return "(".join("|",@re).")"; 
} 
+0

問題的非常漂亮的簡化。 – jm666

2

您一般是在正確的軌道上。我會實現make_word_regex這樣的:

my ($word, $num) = @_; 

# paranoid error checking 
defined $word   or croak "Can't prepare undef value"; 
$num <= length($word) or croak "More characters requested than avaliable"; 
$num >= 1    or croak "Pattern must consist of at least one char"; 

my $regex = ''; # initialize $regex to something we can interpolate w/o warning 

for my $char (reverse split //, substr $word, 0, $num) { 
    # use qr// instead of treating regexes like strings 
    # The \Q ... \E protects for special characters. Always use this for external input. 
    $regex = qr/\Q$char\E $regex?/x; 
} 

return $regex; 

可正常工作,保存的事實,很多不必要的垃圾包括正則表達式裏面(make_word_regex("open", 3)返回一個正則表達式對象可以字符串化到(?x-ism:o (?x-ism:p (?x-ism:e ?)?)?),這取決於你的Perl )。

您可以用類似的方法將這些部分正則表達式組合成一個首字母縮略詞查找器。我會寫make_regex作爲

# assert that every word is followed by a number. 
@_ % 2 == 0 or croak "even number of arguments required."; 

my @regexes; 
while (@_) { 
    my ($word, $num) = splice @_, 0, 2; # shift the first two elems 
    push @regexes, make_word_regex($word, $num); 
} 

# combine the regexes: 
return qr/ \A @regexes \z /x; 

在字符串開頭的\A anchores; \z最後。 /x標誌允許通過包含不匹配的空格來使得正則表達式更具可讀性。

然後,您可以調用腳本就像

$ acrobuild open 3 icebreaker 3 umbrella 2 

我建議不要硬編碼字典文件。管道通過STDIN的字典來代替:

$ acrobuild open 3 icebreaker 3 umbrella 2 </usr/share/dict/web2 

這將簡化您的do_grep

my $re = shift; 
while (<STDIN>) { 
    chomp; 
    say if /$re/i; 
} 
+0

接受另一個答案,因爲他簡單地將問題交給了變更。無論如何,謝謝+1! – kobame

相關問題