Domanda

Dopo aver sentito parlare di Perl per quest'anno ho deciso di dargli un paio di ore del mio tempo per vedere quanto avrei potuto raccogliere. Ho ottenuto attraverso le basi bene e poi avuto modo di loop. Come test ho voluto vedere se ho potuto costruire uno script per recurse attraverso tutti i valori alfanumerici fino a 4 caratteri. Avevo scritto un codice PHP che fece la stessa cosa qualche tempo fa così ho preso lo stesso concetto e lo ha utilizzato. Tuttavia quando si esegue lo script mette "a" come i primi 3 valori e poi loop solo attraverso l'ultima cifra. Chiunque vedere quello che sto facendo male?

#!/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, '');

Questo è ciò che ottengo quando l'eseguo:

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
È stato utile?

Soluzione

Sei stato morso da scoping non rigorosa, questo codice fa quello che dovrebbe (si noti l'uso rigoroso nella parte superiore e il successivo utilizzo del mio per garantire scoping variabile).

#!/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, '');

Altri suggerimenti

Già ben risposto, ma un approccio più idiomatica potrebbe essere:

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);

Non c'è alcun bisogno di posizione di passaggio; è implicito nella larghezza della stringa di base passata. Il set di caratteri, d'altra parte, dovrebbe essere passato in piuttosto che l'uso subroutine una variabile esterna.

In alternativa, dal momento che la larghezza e set di caratteri soggiorno costante, generano una chiusura che li riferimenti:

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->('');

In alternativa, basta:

print "$_\n" for glob(('{' . join(',', 'a'..'z', 'A'..'Z', '0'..'9') . '}') x 4);

Ha a che fare con il campo di applicazione delle variabili, si sta ancora cambiando le stesse variabili quando si sta chiamando la ricorsione. La parola chiave 'mio' dichiara le variabili locali alla subroutine. (Http://perl.plover.com/FAQs/Namespaces.html)

Ho sempre usare perl con 'use strict;' dichiarato, costringendomi a decidere in merito alla portata delle variabili.

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 " ";
  }
}

Sembra che tu stia in esecuzione in alcuni problemi di scoping. Perl è molto flessibile, in modo che sta prendendo una congettura a quello che vuoi perché non hai detto che ciò che si desidera. Una delle prime cose che si impara è di aggiungere use strict; come per la prima dichiarazione dopo la faccenda. Sarà sottolineare le variabili che non vengono esplicitamente definiti, così come tutte le variabili a cui si accede prima di essere creato (aiuta con le variabili errate, ecc).

Se fate il vostro look codice come questo, capirete perché si stanno ottenendo i vostri errori:

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";
}

Questo dovrebbe uscita:

3
3
3
3

Poiché non si scoping $position correttamente con my, non si è trovato una nuova variabile ogni recurse, si è ri-utilizzando lo stesso. Lanciate una use strict; in là, e correggere gli errori che si ottiene, e il codice dovrebbe essere buona.

Mi rendo conto che sei solo armeggiare con la ricorsione. Ma finché ci si diverte a confronto le implementazioni tra due lingue si può anche vedere anche come il CPAN può estendere il set di strumenti.

Se non vi interessa circa l'ordine, è possibile generare tutte le permutazioni di 13,388,280 ( 'a'..'z', 'A..'Z', '0'..'9' ) presi quattro alla volta con il modulo CPAN, Algoritmo :: Permute

Ecco un esempio di come quel codice può sembrare.

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";
}

Il metodo new() accetta un riferimento ad array che elenca il set di caratteri o lista di cosa permutare. Il suo secondo argomento è il numero in un momento da includere nella permutazione. Quindi stai essenzialmente prendendo 62 punti 4 alla volta. Quindi utilizzare il metodo next() per scorrere le permutazioni. Il resto è solo di facciata.

La stessa cosa potrebbe essere ridotto al seguente Perl one-liner:

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

C'è anche una sezione sulla permutazione, insieme ad altri esempi di perlfaq4 . Esso comprende diversi esempi e liste di alcuni moduli aggiuntivi che gestiscono i dettagli per voi. Uno dei punti di forza di Perl è la dimensione e la completezza delle Comprehensive Perl Archive Network (CPAN).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top