Perl - 将字符串扩展为列表。

时间:2016-03-23 18:19:23

标签: perl parsing templates cartesian-product

尝试执行以下操作。

#expand [a] to is, and isn't
#expand [b] to test, and demo
my $string = 'This [a] a [b]';

基本上我最终会以

结束
my @strings = ('This is a test', 'This isn\'t a test', 'This is a demo', 'This isn\'t a demo');

我在使用递归之前已经完成了这个但是这是一个非常大的数据集和很多规则我觉得可能有一个更简单的方法使用map或grep或List :: MoreUtils我只是想不到它的。

1 个答案:

答案 0 :(得分:2)

给出表格的输入

my %dict = (
   a => ["is", "isn't"],
   b => ["test", "demo"],
);

my $template = 'This [a] a [b]';

Algorithm :: Loops version:

use Algorithm::Loops qw( NestedLoops );

my @loops;
for ($template) {
   if (/\G \[ /xgc) {
      /\G ( [^\]]* ) \] /xgc
         or die("Missing \"]\"\n");

      my $var = $1;
      length($var)
         or die("Empty \"[]\"\n");

      $dict{$var}      
         or die("Unknown var \"$var\"\n");

      push @loops, $dict{$var};
      redo;
   }

   if (/\G ( [^\[]+ ) /xgc) {
      push @loops, [ $1 ];
      redo;
   }

   /\G \z /xgc
      or die("Internal error");
}

my $iter = NestedLoops(\@loops);
while (my @parts = $iter->()) {
   print(join('', @parts), "\n");
}

输出:

This is a test
This is a demo
This isn't a test
This isn't a demo

glob - 基于版本:

$_ = '{'.join(',', map quotemeta($_), @$_).'}'
   for values(%dict);

my $glob;
for ($template) {
   if (/\G \[ /xgc) {
      /\G ( [^\]]* ) \] /xgc
         or die("Missing \"]\"\n");

      my $var = $1;
      length($var)
         or die("Empty \"[]\"\n");

      $dict{$var}
         or die("Unknown var \"$var\"\n");

      $glob .= $dict{$var};
      redo;
   }

   if (/\G ( [^\[]+ ) /xgc) {
      $glob .= $1;
      redo;
   }

   /\G \z /xgc
      or die("Internal error");
}

while (defined( my $string = glob($glob) )) {
   print($string, "\n");
}

没有错误检查和特定字典,这可以缩小很多:

$ perl -E'say for glob shift=~s/\[((a)|b)]|(.)/$3?"\Q$3":$1?"{is,isn'\''t}":"{test,demo}"/serg' \
   'This [a] a [b]'
This is a test
This is a demo
This isn't a test
This isn't a demo