Автовосстановление писем в Perl
Я не понимаю автоинкрементных букв в Perl.
Этот пример кажется вполне понятным:
$a = 'bz'; ++$a;
ca #output
b
увеличивается до c
. Для z
ничего не осталось, поэтому он возвращается к a
(или, по крайней мере, так я вижу процесс).
Но затем я нахожу такие утверждения, как это:
$a = 'Zz'; ++$a;
AAa #output
и
$a = '9z'; ++$a;
10 #output
Почему не увеличивается Zz
return Aa
? И почему не увеличивается 9z
return 0z
?
Спасибо!
Ответы
Ответ 1
Чтобы процитировать perlop:
Если, однако, переменная была используется только в строковых контекстах, поскольку был установлен и имеет значение, которое не является пустую строку и соответствует шаблон /^[a-zA-Z]*[0-9]*\z/
, приращение выполняется как строка, сохранение каждого символа в его диапазон, с переносом.
Диапазоны: 0-9, A-Z и a-z. Когда требуется новый символ, он берется из диапазона первого символа. Каждый диапазон независим; символы никогда не покидают диапазон, в котором они начали.
9z
не соответствует шаблону, поэтому он получает числовое значение. (Вероятно, это должно дать предупреждение "Аргумент не числовое", но это не относится к Perl 5.10.1.) Цифрам разрешено только после всех букв (если есть), никогда ранее их.
Обратите внимание, что всезначная строка соответствует шаблону и получает приращение строки (если оно никогда не использовалось в числовом контексте). Однако результат приращения строки в такой строке идентичен числовому приращению, за исключением того, что он имеет бесконечную точность и ведущие нули (если они есть) сохраняются. (Таким образом, вы можете только сказать разницу, когда количество цифр превышает то, что может хранить IV или NV, или имеет ведущие нули.)
Я не понимаю, почему вы думаете, что Zz
должен стать Aa
(если вы не думаете о модульной арифметике, но это не так). Он становится AAa
через этот процесс:
- Приращение
z
округляется до a
. Увеличьте предыдущий символ.
- Приращение
z
обтекает до a
. Нет предыдущего символа, поэтому добавьте первый из этого диапазона, который еще один a
.
Оператор диапазона (..
), когда заданы две строки (и левая часть соответствует шаблону), использует строку increment для создания списка (это объясняется в конце этого раздела). Список начинается с левого операнда, который затем увеличивается до тех пор, пока:
- Значение равно правому операнду или
- Длина значения превышает длину правого операнда.
Он возвращает список всех значений. (Если случай 2 завершает список, окончательное значение не включается в него.)
Ответ 2
-
Потому что (игнорируя случай на данный момент, случай просто сохраняется, ничего интересного с ним не происходит), "AA" является преемником "Z", так как же он может быть преемником "ZZ"? Преемником "ZZ" является "AAA".
-
Так как для ++
и всех других числовых операторов, "9z"
- это просто глупый способ записи 9, а преемником 9 является 10. Специальное строковое поведение автоматического приращения явно указано только для строк букв или строк букв, за которыми следуют номера (и не смешиваются каким-либо другим способом).
Ответ 3
Ответ: не делать этого. Автоматическое приращение ++
с не числами полна неприятных ловушек. Он подходит только для быстрого взлома.
Вам лучше написать свой собственный итератор для такого рода вещей:
#!/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";
}
}
Ответ 4
Вы спрашиваете, почему приращение не обертывается.
Если бы это было так, это не было бы приращением. Для увеличения означает, что у вас есть полностью упорядоченный набор и элемент в нем и создайте следующий более высокий элемент, поэтому он никогда не сможет вернуть вас к нижнему элементу. В этом случае полное упорядочение представляет собой стандартное алфавитное упорядочение строк (которое определяется только на английском алфавите), расширенное, чтобы справиться с произвольными строками ASCII таким образом, который кажется естественным для некоторых общих типов строк идентификатора.
Обтекание также победит его цель: обычно вы хотите использовать его для генерации произвольно многих разных идентификаторов.
Я согласен с вердиктю Chas Owens: применение этой операции к произвольным строкам - плохая идея, что не тот вид использования, для которого она предназначалась.
Я не согласен с его лекарством: просто выберите простое начальное значение, по которому приращение ведет себя здорово, и все будет хорошо.
Ответ 5
Я не понимаю, почему приращение Zz вернет Aa; почему вы думаете, что нужно? Приращение 9z выглядит так, как будто Perl считает, что 9z - это число 9, а не какая-то странность в основе 36.