0

私はこのような文字列を持っています:

$words = "[a] (good|bad) word [for fun]";

どこ:

  1. []内のすべてはオプションです
  2. (.. | ..)内の値はOR必須値です

したがって、上記の文字列から考えられる結果は次のようになります。

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 

誰かが(上記の例のように)考えられるすべての結果を抽出して配列に格納する方法を見つけるのを手伝ってもらえますか?

ありがとう!

4

3 に答える 3

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;
于 2013-03-21T00:51:52.287 に答える
1

正規表現を使用すると、「悪い単語」がパターン「[a](良い|悪い)単語[楽しみのために]」と一致するかどうかを判断できます(正規表現の一致として、おそらく次のように綴られます/(a )?(good|bad) word( for fun)?/)。しかし、実際には逆のことをしたいようです。パターンから可能なすべての入力を生成します。これは正規表現でできることではありません。

あなたが見なければならないのは順列と呼ばれています。テンプレート文字列には次の部分があります。

  1. 「a」または何もない
  2. "良いか悪いか"
  3. " 語"
  4. 「楽しみのために」または何も

したがって、フラグメント1と2には2つの可能性があり、フラグメント3には1つ、フラグメント4には2つあり、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];
于 2013-03-21T00:48:39.130 に答える
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";
}

出力:

楽しみのための良い言葉
良い言葉
楽しみのための悪い言葉
悪い言葉
楽しみのための良い言葉
良い言葉
楽しみのための悪い言葉
悪い言葉
于 2013-03-21T02:39:45.017 に答える