2010-08-18 5 views
11

Je ne comprends pas les lettres auto-incrémentées en Perl.Lettres auto-incrémentées en Perl

Cet exemple semble parfaitement compréhensible:

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

b s'incrémente à c. Il ne reste plus rien à z, donc ça revient à a (ou du moins c'est comme ça que je vois le processus).

Mais je viens à travers des déclarations comme ceci:

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

et:

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

Pourquoi ne pas incrémenter Zz retour Aa? Et pourquoi n'incrémente pas 9z retour 0z?

Merci!

+1

On dirait que dans le contexte auto-incrémenté, 9z, 9a, 9b ou 9zzz123, etc sont identiques. Les éléments non numérotés sont supprimés en silence. – Mike

+0

Il s'agit de caractères incrémentiels.Ce n'est pas essayer de comprendre quel modèle vous voulez. J'en parle un peu dans la nouvelle édition du Learning Perl Student Workbook que j'ai presque fini. :) –

+0

Y at-il un nom pour ce format de "numérotation" en utilisant des lettres, quelqu'un sait-il? – AmbroseChapel

Répondre

22

Pour citer perlop:

Toutefois, si la variable a été utilisé dans un contexte de chaîne que depuis a été définie, et a une valeur qui n'est pas la chaîne vide et correspond au modèle /^[a-zA-Z]*[0-9]*\z/, l'incrément est fait comme une chaîne, en préservant chaque caractère dans sa gamme , avec report.

Les plages sont 0-9, A-Z et a-z. Quand un nouveau personnage est nécessaire, il est pris dans la plage du premier caractère. Chaque gamme est indépendante. les caractères ne quittent jamais la plage dans laquelle ils ont démarré.

9z ne correspond pas au motif, donc il reçoit un incrément numérique. (Il devrait probablement donner un avertissement "Argument n'est pas numérique", mais il ne le fait pas dans Perl 5.10.1.) Les chiffres sont autorisés seulement après toutes les lettres (le cas échéant), jamais avant eux.

Notez qu'une chaîne tous les chiffres ne correspond au modèle, et ne reçoivent un incrément de chaîne (si elle n'a jamais été utilisé dans un contexte numérique). Cependant, le résultat d'un incrément de chaîne sur une telle chaîne est identique à un incrément numérique, sauf qu'il a une précision infinie et que les zéros en tête (le cas échéant) sont conservés. (Vous ne pouvez donc faire la différence que lorsque le nombre de chiffres dépasse ce qu'une IV ou une NV peut stocker, ou qu'il y a des zéros en tête.

Je ne vois pas pourquoi vous pensez Zz devrait devenir Aa (sauf si vous pensez à l'arithmétique modulaire, mais ce n'est pas le cas). Il devient AAa par ce processus:

  1. incrémenter z se enroule autour de a. Incrémente le caractère précédent.
  2. L'incrémentation Z se déroule autour de A. Il n'y a pas de caractère précédent, alors ajoutez le premier de cette plage, qui est un autre A.

Le range operator (..), lorsqu'il est administré deux chaînes (et un correspond au modèle à la main gauche), utilise l'incrément de chaîne pour produire une liste (ceci est expliqué à la fin de cet article). La liste commence par l'opérande gauche, qui est ensuite incrémentée jusqu'à ce que soit:

  1. La valeur est égale à l'opérande de droite, ou
  2. La longueur de la valeur est supérieure à la longueur de l'opérande de droite .

Il renvoie une liste de toutes les valeurs. (Si le cas 2 mis fin à la liste, la valeur finale ne figure pas dans ce.)

+0

Merci pour vos réponses tout le monde. Le problème que j'ai est que je ne comprends pas comment fonctionne l'opérateur de flip flop. Quand je vois aa .. cc je l'image: aa ab ac ca cc cc, mais à la place je deviens a et b tout le chemin jusqu'à z quand je ne le dis pas. – Brian

+0

@Brian, c'est l'opérateur de gamme, pas l'opérateur de bascule. Ils sont orthographiés de la même façon, mais l'un ne se produit que dans un contexte de liste, et l'autre seulement dans un contexte scalaire. – cjm

+0

@Brian, voulez-vous dire que vous ne comprenez pas, ou vous ne comprenez pas? Vous l'avez dit pour générer un ab ... ay az ba bb ... par bz ca cb cc (même si ce n'est pas ce que vous vouliez dire). – cjm

0

Je ne vois pas pourquoi l'incrémentation de Zz retournerait Aa; pourquoi pensez-vous qu'il devrait? 9z incrémentant ressemble à Perl pense que 9z est un numéro 9 plutôt qu'une sorte d'étrangeté de base-36.

3

La réponse est de ne pas faire cela. L'incrémentation automagique de ++ avec des non-nombres est pleine de pièges méchants. Il est adapté uniquement pour les hacks rapides.

Vous êtes mieux d'écrire votre propre itérateur pour ce genre de chose:

#!/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'accord avec Chas. Certaines des caractéristiques les plus ésotériques de Perl sont mieux laissées seules pour la clarté du code. Vous ne comprendrez probablement pas une chose que vous avez écrite après un certain temps si vous utilisez ces fonctionnalités obscures. – GeneQ

6
  1. Parce que (en ignorant la casse pour le moment, le cas est simplement conservé, rien d'intéressant se passe avec elle), « AA » est le successeur de 'Z', alors comment pourrait-il être aussi le successeur de 'ZZ'? Le successeur de 'ZZ' est 'AAA'.

  2. Parce que dans la mesure où ++ et tous les autres opérateurs numériques sont concernés, "9z" est juste une façon stupide d'écrire 9, et le successeur de 9 est 10. Le comportement de chaîne spéciale d'auto-incrément est clairement spécifié seulement se produire sur des chaînes de lettres, ou des chaînes de lettres suivies de chiffres (et non mélangées d'une autre manière).

2

Vous demandez pourquoi l'incrément ne s'enroule pas.

Si cela l'était, ce ne serait pas vraiment un incrément. Incrémenter signifie que vous disposez d'un ensemble totalement ordonné et d'un élément et que vous produisez l'élément supérieur suivant, de sorte qu'il ne peut jamais vous ramener à un élément inférieur. Dans ce cas, la commande totale est l'ordre alphabétique standard des chaînes (qui est seulement défini sur l'alphabet anglais), étendu pour faire face aux chaînes ASCII arbitraires d'une manière qui semble naturelle pour certains types communs de chaînes d'identifiants. Wrapping serait également vaincre son but: généralement, vous voulez l'utiliser pour générer arbitrairement beaucoup d'identifiants différents d'une certaine sorte.

Je suis d'accord avec le verdict de Chas Owens: appliquer cette opération à arbitraires est une mauvaise idée, ce n'est pas le genre d'utilisation pour laquelle il était destiné.

Je suis en désaccord avec son remède: il suffit de choisir une valeur de départ simple sur laquelle l'incrément se comporte correctement, et tout ira bien.