2010-08-18 9 views
11

Nie rozumiem autoinrementacji liter w Perlu.Auto-inkrementacja liter w Perlu

Przykład ten wydaje się całkiem zrozumiałe:

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

b zostanie zwiększony do c. Nie ma już nic do przejścia na z, więc wraca do a (a przynajmniej tak widzę proces).

Ale potem natknąć wypowiedzi tak:

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

i:

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

Dlaczego nie zwiększając Zz zwrot Aa? I dlaczego nie zwiększa się 9z return 0z?

Dzięki!

+1

Wygląda na to, że w kontekście autoreferencji 9z, 9a, 9b lub 9zzz123 itp. Są takie same. Trasowanie niezliczonej ilości rzeczy jest po cichu odrzucane. – Mike

+0

Inkrementuje postacie.To nie próbuje dowiedzieć się, jaki wzór chcesz. Mówię o tym trochę w nowym wydaniu Podręcznika uczniowskiego uczenia się, który już prawie skończyłem. :) –

+0

Czy istnieje nazwa tego "numerowania" formatu przy użyciu liter, czy ktoś wie? – AmbroseChapel

Odpowiedz

22

Cytując perlop:

Jeśli jednak zmienna została stosowany tylko w kontekstach łańcuchowych został ustawiony i ma wartość, która nie jest pusty ciąg i pasuje do wzór /^[a-zA-Z]*[0-9]*\z/, przyrost o jest wykonywany jako ciąg znaków, zachowując każdy znak w zakresie z przenoszeniem.

Zakresy to 0-9, A-Z i a-z. Kiedy nowa postać jest potrzebna, jest pobierana z zakresu pierwszego znaku. Każdy zakres jest niezależny; znaki nigdy nie opuszczają zakresu, w którym zaczynały.

9z nie pasuje do wzorca, więc otrzymuje przyrost liczbowy. (Prawdopodobnie powinien dać ostrzeżenie "Argument is not numeric", ale nie w Perlu 5.10.1.) Cyfry są dozwolone tylko po wszystkich liter (jeśli są), nigdy przed nimi.

pamiętać, że cały ciąg cyfr robi pasuje do wzorca, a robi otrzymać przyrost string (jeśli to nigdy nie zostało użyte w kontekście numerycznej). Jednak wynik przyrostu łańcucha na takim łańcuchu jest identyczny z przyrostem numerycznym, z tym że ma on nieskończoną dokładność i początkowe zera (jeśli są) są zachowane. (W ten sposób można stwierdzić różnicę tylko wtedy, gdy liczba cyfr przekracza pojemność IV lub NV, lub ma początkowe zera.)

Nie rozumiem, dlaczego uważasz, że Zz powinno stać się Aa (chyba że myślisz o modularnej arytmetyki, ale tak nie jest). Staje AAa w tym procesie:

  1. Zwiększanie z otacza się a. Zwiększ poprzedni znak.
  2. Inkrementacja Z zawija się do numeru A. Nie ma poprzedniej postaci, więc dodaj pierwszą z tego zakresu, czyli inną A.

range operator (..), gdy podane dwa ciągi (i jeden lewy pasuje do wzorca), wykorzystuje przyrost ciąg produkować listę (to wyjaśnione pod koniec tego rozdziału). Lista zaczyna się od argumentu po lewej stronie, która jest następnie zwiększany aż do:

  1. Wartość równa argument prawy lub
  2. Długość wartość przekracza długość argumentu prawostronnego .

Powoduje wyświetlenie listy wszystkich wartości. (Jeśli przypadek 2 rozwiązana listy, wartość końcowa nie jest w nim zawarte.)

+0

Dziękuję za wszystkie odpowiedzi. Problem w tym, że nie rozumiem, jak działa operator flip flopa. Kiedy widzę aa .. cc I obraz: aa ab ac cb cc, ale zamiast tego dostaję aib, idąc całą drogę do z, kiedy nie powiedziałem tego. – Brian

+0

@Brian, to operator zasięgu, a nie operator flip-flop. Są pisane tak samo, ale jeden występuje tylko w kontekście listy, a drugi tylko w kontekście skalarnym. – cjm

+0

@Brian, masz na myśli, że nie rozumiesz, lub nie rozumiesz? Powiedziałeś, żeby wygenerować aa ab ... ay az ba bb ... przez bz ca cb cc (nawet jeśli nie to miałeś na myśli). – cjm

0

Nie rozumiem, dlaczego inwertowanie Zz zwróciłoby Aa; dlaczego uważasz, że powinno? Zwiększenie 9z wygląda na to, że Perl uważa, że ​​9z to numer 9, a nie jakaś dziwaczność bazowa-36.

3

Odpowiedź brzmi: nie rób tego. Automagiczny wzrost liczby ++ z liczbami jest pełen nieprzyjemnych pułapek. Nadaje się tylko do szybkich hacków.

Jesteś lepiej pisanie własnego iterator dla tego typu rzeczy:

#!/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

Zgadzam się z Chas. Niektóre z bardziej ezoterycznych cech Perla najlepiej pozostawić w spokoju, aby uzyskać przejrzystość kodu. Prawdopodobnie nie zrozumiesz czegoś, co napisałeś po jakimś czasie, jeśli użyjesz tych niejasnych funkcji. – GeneQ

6
  1. ponieważ (pomijając przypadek na chwilę; sprawa jest tylko zachowane, nic ciekawego dzieje się z nim), „AA” jest następca "Z", więc jak może to być także następca "ZZ"? Następcą "ZZ" jest "AAA".

  2. bo o ile ++ i wszystkie inne podmioty liczbowe są zainteresowane, "9z" jest po prostu głupi sposób pisania 9, a następcą 9 10. Specjalny zachowanie ciąg automatycznego przyrostu jest jasno określony tylko wystąpić na ciągi liter lub ciągi liter, po których następują liczby (i nie są zmieszane w żaden inny sposób).

2

Pytasz, dlaczego inkrementacja się nie obraca.

Jeśli tak, to naprawdę nie będzie inkrementacja. Aby zwiększyć, oznacza to, że masz kompletnie uporządkowany zestaw i element w nim, tworząc następny wyższy element, dzięki czemu nigdy nie przeniesie Cię z powrotem do niższego elementu. W tym przypadku całkowita kolejność jest standardowym porządkiem alfabetycznym ciągów znaków (który jest zdefiniowany tylko w alfabecie angielskim), rozszerzonym tak, aby poradzić sobie z arbitralnymi ciągami znaków ASCII w sposób, który wydaje się naturalny dla pewnych popularnych typów ciągów identyfikatorów.

Zawijanie również nie przyniosłoby zamierzonego rezultatu: zwykle ma to na celu wygenerowanie dowolnie wielu różnych identyfikatorów.

Zgadzam się z wyrokiem Chas Owens: zastosowanie tej operacji do arbitralnych ciągów znaków jest złym pomysłem, nie jest to rodzaj użytkowania, dla którego był przeznaczony.

Nie zgadzam się z jego środkiem zaradczym: po prostu wybierz prostą wartość początkową, przy której przyrost zachowuje się zdrowo, a wszystko będzie dobrze.