2013-04-18 50 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

相关问题