2

Perlについて何年も聞いていたので、私はそれを数時間与えて、どれだけ手に入れることができるかを確認することにしました。私は基本をうまくやり遂げて、それからループに行きました。テストとして、最大4文字のすべての英数字の値を再帰的に処理するスクリプトを作成できるかどうかを確認したいと思いました。しばらく前に同じことをするPHPコードを書いていたので、同じ概念を採用して使用しました。ただし、スクリプトを実行すると、最初の3つの値として「a」が設定され、最後の桁のみがループされます。誰かが私が間違っているのを見ますか?

#!/usr/local/bin/perl 

$chars = "abcdefghijklmnopqrstuvwxyz";
$chars .= "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$chars .= "0123456789";

@charset = split(//, $chars);

$charset_length = scalar(@charset);

sub recurse
{
 ($width, $position, $base_string) = @_;

for ($i = 0; $i < $charset_length; ++$i) {
    $base = $base_string . $charset[$i];
    if ($position < $width - 1) {
        $pos = $position + 1;
        recurse($width, $pos, $base);
    }
    print $base;
    print "\n";
}
}

recurse(4, 0, '');

これは私がそれを実行したときに私が得るものです:

aaaa
aaab
aaac
aaad
aaae
aaaf
aaag
aaah
aaai
aaaj
aaak
aaal
aaam
aaan
aaao
aaap
aaaq
aaar
aaas
aaat
aaau
aaav
aaaw
aaax
aaay
aaaz
aaaA
aaaB
aaaC
aaaD
aaaE
aaaF
aaaG
aaaH
aaaI
aaaJ
aaaK
aaaL
aaaM
aaaN
aaaO
aaaP
aaaQ
aaaR
aaaS
aaaT
aaaU
aaaV
aaaW
aaaX
aaaY
aaaZ
aaa0
aaa1
aaa2
aaa3
aaa4
aaa5
aaa6
aaa7
aaa8
aaa9
aaa9
aaa9
aaa9
4

5 に答える 5

12

あなたは非厳密なスコープに噛まれてきました、このコードはそれがすべきことをします(上部での厳密な使用とそれに続く変数のスコープを保証するためのmyの使用に注意してください)。

#!/usr/bin/env perl
use strict;
use warnings;

my $chars = "abcdefghijklmnopqrstuvwxyz";
$chars .= "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$chars .= "0123456789";

my @charset = split(//, $chars);

my $charset_length = scalar(@charset);

sub recurse {
    my ($width, $position, $base_string) = @_;

    for (my $i = 0; $i < $charset_length; ++$i) {
        my $base = $base_string . $charset[$i];

        if ($position < $width - 1) {
            my $pos = $position + 1;
            recurse($width, $pos, $base);
        }

        print $base;
        print "\n";
    }
}

recurse(4, 0, '');
于 2011-07-25T17:25:20.413 に答える
10

すでによく答えられていますが、より慣用的なアプローチは次のようになります。

use strict;
use warnings;

sub recurse {
    my ($width, $base_string, $charset) = @_;

    if (length $base_string) {
        print "$base_string\n";
    }
    if (length($base_string) < $width) {
        $recurser->($base_string . $_) for @$charset;
    }
}

my @charset = ('a'..'z', 'A'..'Z', '0'..'9');
recurse(4, '', \@charset);

ポジションを渡す必要はありません。渡されるベース文字列の幅に暗黙的に含まれます。一方、文字セットは、サブルーチンに外部変数を使用させるのではなく、渡される必要があります。

または、幅と文字セットは一定のままなので、それらを参照するクロージャを生成します。

use strict;
use warnings;

sub make_recurser {
    my ($width, $charset) = @_;
    my $recurser;
    $recurser = sub {
        my ($base_string) = @_;

        if (length $base_string) {
            print "$base_string\n";
        }
        if (length($base_string) < $width) {
            $recurser->($base_string . $_) for @$charset;
        }
    }
}

my @charset = ('a'..'z', 'A'..'Z', '0'..'9');
my $recurser = make_recurser(4, \@charset);
$recurser->('');

または、次のようにします。

print "$_\n" for glob(('{' . join(',', 'a'..'z', 'A'..'Z', '0'..'9') . '}') x 4);
于 2011-07-25T18:05:29.997 に答える
4

これは変数のスコープと関係があり、再帰を呼び出すときに同じ変数を変更します。キーワード「my」は、サブルーチンに対してローカルな変数を宣言します。(http://perl.plover.com/FAQs/Namespaces.html)

私はいつもperlを'usestrict;'で使用します。宣言され、変数のスコープを決定するように強制されました。

sub recurse {
  my ($width, $position, $base_string) = @_;
  for (my $i = 0; $i < $charset_length; ++$i) {
    my $base = $base_string . $charset[$i];
    if ($position < $width - 1) {
      my $pos = $position + 1;
      recurse($width, $pos, $base);
    }
    print $base;
    print " ";
  }
}
于 2011-07-25T17:25:47.117 に答える
4

スコープの問題が発生しているようです。Perlは非常に柔軟性があり、必要なものを伝えていないため、必要なものを推測しています。最初に学ぶことの1つはuse strict;、シェバンの後の最初のステートメントを追加することです。明示的に定義されていない変数、および作成前にアクセスされる変数(スペルミスのある変数などに役立ちます)を示します。

コードを次のようにすると、エラーが発生する理由がわかります。

sub recurse {
    ($width, $position, $base_string) = @_;

    for ($i = 0; $i < $charset_length; ++$i) {
        $base = $base_string . $charset[$i];
        if ($position < $width - 1) {
            $pos = $position + 1;
            recurse($width, $pos, $base);
        }
        # print "$base\n";
    }
    print "$position\n";
}

これは出力するはずです:

3
3
3
3

$positionで正しくスコープを設定していないためmy、再帰ごとに新しい変数を取得することはなく、同じ変数を再利用しています。そこに投げて、use strict;あなたが得るエラーを修正してください、そしてコードは良いはずです。

于 2011-07-25T17:29:47.763 に答える
2

あなたは再帰をいじくり回しているだけだと思います。ただし、2つの言語間の実装を比較することを楽しんでいる限り、CPANがツールセットをどのように拡張できるかを確認することもできます。

順序を気にしない場合は( 'a'..'z', 'A..'Z', '0'..'9' )、CPANモジュールAlgorithm :: Permuteを使用して、一度に4つ取得した13,388,280の順列をすべて生成できます。

そのコードがどのように見えるかの例を次に示します。

use strict;
use warnings;
use Algorithm::Permute;

my $p = Algorithm::Permute->new( 
    [ 'a' .. 'z', 'A' .. 'Z', '0' .. '9' ], # Set of...
    4 # <---- at a time.
);

while ( my @res = $p->next ) {
    print @res, "\n";
}

このnew()メソッドは、置換する文字セットまたはリストを列挙する配列refを受け入れます。その2番目の引数は、順列に含める一度の数です。つまり、基本的に一度に62個のアイテムを4個取っています。次に、このnext()メソッドを使用して順列を反復処理します。残りはただのウィンドウドレッシングです。

同じことを次のPerlワンライナーに減らすことができます。

perl -MAlgorithm::Permute -e '$p=Algorithm::Permute->new(["a".."z","A".."Z",0..9],4);print @r, "\n" while @r=$p->next;'

perlfaq4の追加の例とともに、順列に関するセクションもあります。いくつかの例が含まれており、詳細を処理するいくつかの追加モジュールがリストされています。Perlの強みの1つは、包括的なPerlアーカイブネットワーク(CPAN)のサイズと完全性です。

于 2011-07-25T18:16:41.823 に答える