有N
个定义的单词,对于这个问题3个单词,例如:open
icebreaker
umbrela
。
在这里想知道英语单词存在的任何可能的首字母缩略词,例如想要运行类似的东西:
grep -Pi '^o(p(e?))?i(c(e?))?um?$' my_long_wordlist.txt
在上面的正则表达式我决定然后我可以使用
o
,或op
或ope
(第一个,或前两个,或前三个字母)i
,或ic
或ice
(第一个,或前两个,或前三个字母)u
或um
为了好玩 - 上面的正则表达式将为我返回单词:opium
:)
手动构建正则表达式 对于两个测试是可以接受的,但我想检查多个单词组合,所以,寻找如何生成如上所述的正则表达式的方法。
想要通过以下调用构建“首字母缩略词查找器正则表达式脚本”:
acrobuild open:4 icebreaker:3 umbrela:3
正如您所看到的,args是单词,分隔符后面的数字是从开头可以在首字母缩略词中使用的最大字母数。
现在的问题 - 我完全失去了如何为给定长度构建正则表达式。需要一些提示,想法或类似的东西.. - 检查“需要帮助在这里”:))
目前我有这个:
#!/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);
}
答案 0 :(得分:2)
而不是嵌套的正则表达式o(p(e?)?)
,我只会列出备选项列表:(o|op|ope)
。
sub make_regex_word {
my ($word)=@_;
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).")";
}
答案 1 :(得分: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)之外,这可以正常工作。< / p>
您可以以类似的方式将这些部分正则表达式组合到首字母缩写词查找器中。我写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
锚点;最后\z
。 /x
标志允许通过包含不匹配的空格来使正则表达式更具可读性。
然后您可以像
一样调用脚本$ acrobuild open 3 icebreaker 3 umbrella 2
我建议不要硬编码字典文件。通过STDIN管道dict:
$ acrobuild open 3 icebreaker 3 umbrella 2 </usr/share/dict/web2
这会简化您的do_grep
到
my $re = shift;
while (<STDIN>) {
chomp;
say if /$re/i;
}