2010-08-18 6 views
11

Non capisco le lettere di autoincremento in Perl.Autoincrementing letters in Perl

Questo esempio sembra perfettamente comprensibile:

$a = 'bz'; ++$a; 
ca #output 

b ottiene incrementato a c. Non è rimasto nulla per z per andare, quindi torna a a (o almeno questo è come vedo il processo).

Ma poi mi imbatto in dichiarazioni come questa:

$a = 'Zz'; ++$a; 
AAa #output 

e:

$a = '9z'; ++$a; 
10 #output 

Perché non incrementare Zz ritorno Aa? E perché l'incremento non 9z restituisce 0z?

Grazie!

+1

Sembra che nel contesto di autoincremento, 9z, 9a, 9b o 9zzz123, ecc. Siano uguali. Il materiale non numerico finale viene scartato in silenzio. – Mike

+0

Si tratta di caratteri incrementali.Non sta cercando di capire quale schema tu voglia. Ne parlo un po 'nella nuova edizione del libro di esercizi per studenti Learning Perl che ho quasi finito. :) –

+0

Esiste un nome per questo formato di "numerazione" utilizzando lettere, qualcuno lo sa? – AmbroseChapel

risposta

22

Per citare perlop:

Se, tuttavia, la variabile è stata utilizzato solo in contesti di stringa dal it è stato impostato e ha un valore che non è la stringa vuota e corrisponde al modello /^[a-zA-Z]*[0-9]*\z/, l'incremento viene eseguito come una stringa, preservando ciascun carattere nel suo intervallo , con carry.

Gli intervalli sono 0-9, A-Z e a-z. Quando è necessario un nuovo personaggio, viene preso dal raggio del primo carattere. Ogni intervallo è indipendente; i caratteri non escono mai dalla gamma iniziale.

9z non corrisponde al modello, quindi ottiene un incremento numerico. (Probabilmente dovrebbe dare un avviso "Argomento non numerico", ma non in Perl 5.10.1.) Le cifre sono consentite solo dopo tutte le lettere (se presenti), mai prima di loro.

Si noti che questa corda in cifre fa corrispondono al modello, e fa ricevono un incremento di stringa (se non è mai stato utilizzato in un contesto numerico). Tuttavia, il risultato di un incremento di stringa su una stringa di questo tipo è identico a un incremento numerico, tranne per il fatto che ha una precisione infinita e gli zero iniziali (se presenti) vengono preservati. (In questo modo è possibile distinguere solo quando il numero di cifre supera quello che una IV o NV può memorizzare, oppure ha zero iniziali.)

Non vedo perché si pensa che Zz diventi Aa (a meno che non si stia pensando all'aritmetica modulare, ma non lo è). Diventa AAa attraverso questo processo:

  1. Incremento z avvolge intorno al a. Incrementa il personaggio precedente.
  2. L'incremento Z si estende attorno a A. Non esiste un carattere precedente, quindi aggiungi il primo da questo intervallo, che è un altro A.

Il range operator (..), quando somministrati due stringhe (e quello sinistro corrisponde al modello), utilizza l'incremento stringa per produrre un elenco (questo è spiegato in prossimità dell'estremità di quella sezione). L'elenco inizia con l'operando di sinistra, che viene quindi incrementato fino:

  1. Il valore è uguale operando a destra, o
  2. la lunghezza del valore supera la lunghezza dell'operando destro .

Restituisce un elenco di tutti i valori. (Se il telaio 2 terminato l'elenco, il valore finale non è incluso in esso.)

+0

Grazie per le tue risposte a tutti. Il problema che sto avendo è che non capisco come funziona l'operatore di infradito. Quando vedo aa .. cc I picture: aa ab ac ca cc cc, ma invece sto ottenendo a e b andando fino a z quando non l'ho detto a. – Brian

+0

@Brian, questo è l'operatore di intervallo, non l'operatore di flip-flop. Sono scritti allo stesso modo, ma uno si verifica solo nel contesto dell'elenco e l'altro solo nel contesto scalare. – cjm

+0

@ Brian, intendi che non capisci o non hai capito? Hai detto di generare aa ab ... ay az ba bb ... di bz ca cb cc (anche se non è quello che intendevi dire). – cjm

0

Non vedo perché l'incremento di Zz restituisca Aa; perché pensi che dovrebbe? 9z di incremento sembra che Perl pensi che 9z sia un numero 9 piuttosto che un qualche tipo di stranezza di base-36.

3

La risposta è non farlo. L'incremento automagico di ++ con numeri diversi è pieno di insidie. È adatto solo per hack rapidi.

Si sta meglio a scrivere il proprio iteratore per questo genere di cose:

#!/usr/bin/perl 

use strict; 
use warnings; 

{ package StringIter; 

    sub new { 
     my $class = shift; 
     my %self = @_; 
     $self{set} = ["a" .. "z"] unless exists $self{set}; 
     $self{value} = -1   unless exists $self{value}; 
     $self{size} = @{$self{set}}; 

     return bless \%self, $class; 
    } 

    sub increment { 
     my $self = shift; 
     $self->{value}++; 
    } 

    sub current { 
     my $self = shift; 
     my $n = $self->{value}; 
     my $size = $self->{size}; 
     my $s = ""; 

     while ($n >= $size) { 
      my $offset = $n % $size; 
      $s   = $self->{set}[$offset] . $s; 
      $n   /= $size; 
     } 
     $s = $self->{set}[$n] . $s; 

     return $s; 
    } 

    sub next { 
     my $self = shift; 
     $self->increment; 
     return $self->current; 
    } 
} 

{ 
    my $iter = StringIter->new; 

    for (1 .. 100) { 
     print $iter->next, "\n"; 
    } 
} 

{ 
    my $iter = StringIter->new(set => [0, 1]); 

    for (1 .. 7) { 
     print $iter->next, "\n"; 
    } 
} 
+0

D'accordo con Chas. Alcune delle caratteristiche più esoteriche di Perl sono meglio lasciate da sole per la chiarezza del codice. Probabilmente non capirai una cosa che hai scritto dopo un po 'se usi queste caratteristiche oscure. – GeneQ

6
  1. Poiché (caso ignorando per il momento; cassa è semplicemente conservata, nulla interessante accade con esso), 'AA' è il successore di "Z", quindi come potrebbe anche essere il successore di "ZZ"? Il successore di "ZZ" è "AAA".

  2. Poiché quanto ++ e tutti gli altri operatori numerici sono interessati, "9z" è solo un modo stupido di scrivere 9, e il successore 9 è 10. Il comportamento speciale stringa di incremento automatico è chiaramente specificato verificarsi solo su stringhe di lettere o stringhe di lettere seguite da numeri (e non mescolate in nessun altro modo).

2

Ti stai chiedendo perché l'incremento non si avvolge.

Se così fosse, non sarebbe davvero un incremento. Aumentare significa avere un set totalmente ordinato e un elemento in esso e produrre il prossimo elemento superiore, in modo che non possa mai tornare a un elemento inferiore. In questo caso l'ordinamento totale è l'ordinamento alfabetico standard delle stringhe (che è definito solo sull'alfabeto inglese), esteso per far fronte a stringhe ASCII arbitrarie in un modo che sembra naturale per alcuni tipi comuni di stringhe identificatore.

Il wrapping potrebbe anche vanificare il suo scopo: in genere si desidera utilizzarlo per generare arbitrariamente molti identificatori diversi di qualche tipo.

Sono d'accordo con il verdetto di Chas Owens: applicare questa operazione alle stringhe arbitrarie è una cattiva idea, non è il tipo di utilizzo a cui era destinato.

Non sono d'accordo con il suo rimedio: basta scegliere un semplice valore iniziale su cui l'incremento si comporta in modo sano, e starai bene.