我有一个这样的字符串:
$words = "[a] (good|bad) word [for fun]";
其中:
因此,上述字符串的可能结果如下:
a good word for fun
a bad word for fun
a good word
a bad Word
good word for fun
bad word for fun
good word
bad word
有人可以帮我找到一种方法来提取所有可能的结果(比如上面的例子)并将它们存储在一个数组中吗?
谢谢!
答案 0 :(得分:2)
use warnings;
use strict;
use constant { OPT => 0, OR => 1, FIXED => 2 };
my $words = "[a] (good|bad) word [for fun]";
my @tokens;
# parse input
my @v = grep {$_} split /(\[|\]|\(|\||\))/, $words;
while (my $token = shift @v) {
if ($token eq '[') {
push @tokens, [ OPT, shift @v ];
shift @v; # ]
} elsif ($token eq '(') {
my @list;
do {
push (@list, [ FIXED, shift @v] );
} until (shift @v eq ')'); # '|,)'
push @tokens, [ OR, \@list ];
}
else {
push @tokens, [FIXED, $token];
}
}
# generate output
my @phrases = ("");
for my $token (@tokens) {
my @additions;
if ($token->[0] == OPT) {
push @additions, $_.$token->[1] for @phrases;
} elsif ($token->[0] == FIXED) {
$_ .= $token->[1] for @phrases;
} elsif ($token->[0] == OR) {
foreach my $list (@{$token->[1]}) {
push @additions, $_.$list->[1] for @phrases;
}
@phrases = ();
}
push @phrases, @additions;
}
print "$_\n" for map {s/^\s+//;s/[ ]+/ /g;$_} @phrases;
答案 1 :(得分:1)
使用正则表达式,您可以确定“坏词”是否与您的模式“[a](好|坏)词[为了好玩]”相匹配“(正如正则表达式匹配,可能拼写为/(a )?(good|bad) word( for fun)?/
)。但听起来你真的想反过来,即。从您的模式生成所有可能的输入。这不是正则表达式可以做的事情。
您应该关注的是排列。您的模板字符串包含以下部分:
因此片段1和2有两种可能性,片段3只有一种,片段4有两种,给你2 * 2 * 1 * 2 = 8种可能性。
只需将所有这些可能性存储在多维数组中,例如
my $sentence = [["a ", ""], ["good", "bad"], ["word"], ["for fun", ""]];
然后在CPAN上查找排列算法或置换模块以找到所有组合。
作为单个排列的示例,“坏词”将表示为:
my $badword =
$sentence->[0]->[0]
. $sentence->[1]->[1]
. $sentence->[2]->[0]
. $sentence->[3]->[0];
答案 2 :(得分:1)
我认为这是尝试使用Parse::RecDescent的机会。我不太了解这些事情,所以可能有更好的方法来编写语法。
解析器允许我生成要使用的短语集列表。然后,我将该组列表提供给Set::CrossProduct以生成集合的笛卡尔积。
#!/usr/bin/env perl
use strict;
use warnings;
use Parse::RecDescent;
use Set::CrossProduct;
our @list;
my $parser = Parse::RecDescent->new(q{
List: OptionalPhrase |
AlternatingMandatoryPhrases |
FixedPhrase
OptionalPhrase:
OptionalPhraseStart
OptionalPhraseContent
OptionalPhraseEnd
OptionalPhraseStart: /\\[/
OptionalPhraseContent: /[^\\]]+/
{
push @::list, [ $item[-1], '' ];
}
OptionalPhraseEnd: /\\]/
AlternatingMandatoryPhrases:
AlternatingMandatoryPhrasesStart
AlternatingMandatoryPhrasesContent
AlternatingMandatoryPhraseEnd
AlternatingMandatoryPhrasesStart: /\\(/
AlternatingMandatoryPhrasesContent: /[^|)]+(?:[|][^|)]+)*/
{
push @::list, [ split /[|]/, $item[-1] ];
}
AlternatingMandatoryPhraseEnd: /\\)/
FixedPhrase: /[^\\[\\]()]+/
{
$item[-1] =~ s/\\A\\s+//;
$item[-1] =~ s/\s+\z//;
push @::list, [ $item[-1] ];
}
});
my $words = "[a] (good|bad) word [for fun]";
1 while defined $parser->List(\$words);
my $iterator = Set::CrossProduct->new(\@list);
while (my $next = $iterator->get) {
print join(' ', grep length, @$next), "\n";
}
输出:
a good word for fun a good word a bad word for fun a bad word good word for fun good word bad word for fun bad word