Autoincrementing letters in Perl

I do not understand autoincrementing letters in Perl.

This example seems perfectly understandable:

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

b gets incremented to c. There is nothing left for z to go to, so it goes back to a (or at least this is how I see the process).

But then I come across statements like this:

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

and:

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

Why doesn't incrementing Zz return Aa? And why doesn't incrementing 9z return 0z?

Thanks!

12
задан Brian 1 November 2011 в 23:53
поделиться

5 ответов

Процитируем perlop :

Если, однако, переменная была используется только в строковом контексте, поскольку он был установлен и имеет значение, отличное от пустая строка и соответствует шаблон / ^ [a-zA-Z] * [0-9] * \ z / , приращение выполняется в виде строки, сохранение каждого персонажа в его диапазон, с переноской.

Диапазон значений: 0–9, A – Z и a – z. Когда нужен новый символ, он берется из диапазона первого символа. Каждый диапазон независим; символы никогда не покидают диапазон, в котором они начали.

9z не соответствует шаблону, поэтому он получает числовое приращение. (Вероятно, он должен выдавать предупреждение «Аргумент не числовой», но этого не происходит в Perl 5.10.1.) Цифры разрешены только после всех букв (если есть), никогда перед ними .

Обратите внимание, что строка, состоящая из всех цифр , соответствует шаблону, а получает приращение строки (если оно никогда не использовалось в числовом контексте). Однако результат приращения такой строки идентичен числовому приращению, за исключением того, что он имеет бесконечную точность и ведущие нули (если есть) сохраняются. (Таким образом, вы можете увидеть разницу только тогда, когда количество цифр превышает то, что может хранить IV или NV, или если оно имеет начальные нули.)

Я не понимаю, почему вы думаете, что Zz должно стать Aa (если вы не думаете о модульной арифметике, но это не так). В результате этого процесса он становится AAa :

  1. Приращение z оборачивается до a . Увеличение предыдущего символа.
  2. При увеличении Z выполняется переход к A . Предыдущего символа нет, поэтому добавьте первый из этого диапазона, то есть еще один A .

Оператор диапазона ( .. ), когда заданы две строки (и левая строка соответствует шаблону), использует приращение строки для создания списка (это объяснено в конце этого раздела). Список начинается с левого операнда, который затем увеличивается до тех пор, пока либо:

  1. Значение не будет равно правому операнду, либо
  2. Длина значения превышает длину правого операнда.

Возвращает список всех значений. (Если случай 2 завершает список, окончательное значение в него не включается.)

23
ответ дан 2 December 2019 в 04:32
поделиться
  1. Потому что (игнорируя на данный момент регистр; регистр просто сохранен, с ним ничего интересного не происходит), «AA» является преемником «Z», так как же он может быть преемником для «ZZ»? Преемник ZZ - AAA.

  2. Поскольку что касается ++ и всех других числовых операторов, «9z» - это просто глупый способ написания 9, а преемником 9 является 10. специальное строковое поведение автоинкремента четко указано, что оно встречается только в строках букв или строках букв, за которыми следуют числа (и не смешиваются каким-либо другим образом).

6
ответ дан 2 December 2019 в 04:32
поделиться

Я не понимаю, почему увеличение Zz вернет Aa; как вы думаете, почему это должно быть? Увеличение 9z выглядит так, как будто Perl думает, что 9z - это число 9, а не какая-то странность с основанием 36.

0
ответ дан 2 December 2019 в 04:32
поделиться

Вы спрашиваете, почему инкремент не зацикливается.

Если бы это было так, это не было бы приращением. Увеличение означает, что у вас есть полностью упорядоченный набор и элемент в нем, и вы создаете следующий более высокий элемент, поэтому он никогда не сможет вернуть вас к более низкому элементу. В этом случае общий порядок - это стандартный алфавитный порядок строк (который определен только для английского алфавита), расширенный для работы с произвольными строками ASCII способом, который кажется естественным для некоторых распространенных типов строк идентификаторов.

Обертывание также лишило бы его цели: обычно вы хотите использовать его для генерации произвольного количества различных идентификаторов того или иного типа.

Я согласен с вердиктом Часа Оуэнса: применение этой операции к произвольным строкам - плохая идея, это не тот вид использования, для которого она была предназначена.

Я не согласен с его решением: просто выберите простое начальное значение, при котором инкремент будет вести себя нормально, и все будет в порядке.

2
ответ дан 2 December 2019 в 04:32
поделиться

Ответ - не делать этого. Автоматическое увеличение числа ++ не-числами полно неприятных ловушек. Подходит только для быстрых взломов.

Лучше написать собственный итератор для такого рода вещей:

#!/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";
    }
}
3
ответ дан 2 December 2019 в 04:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: