Saturday, January 21, 2012

Auto_increment magic behavior (Perl)

1. Задача

Недавно в рассылке moscow.pm увидел небольшую задачку, вроде бы ничего особенного?

$perl -E '$s1="a1"; $s2="1a"; $s3="az"; say ++$s1; say ++$s2;'
a2
2
ba

Показал ее коллегам, многие дали верный ответ, но никто не смог объяснить.

2. Auto_increment (++)

Из офиц. документации следует, что auto_increment работает двумя способами:
- обычный инкремент чисел
- магический инкремент строк

2.1 Инкремент чисел

Если перед операцией инкремента проводили действия над переменной в числовом контексте, то инкремент будет выполнен как для числа, тут все просто.

$str = "abc1";
$str += 0;
say ++$str;

Output: 1

2.2 Инкремент строк

Выполняется только при соблюдении следующих условий:
- переменная не пуста (содержит строку)
- переменная использовалась до этого только в текстовом контексте
- и соответсвует регулярному выражения /^[a-zA-Z]*[0-9]*\z/

Иначе проводится преобразование к числовому контексту и используется обычный инкремент чисел.

2.3 Алгорит инкремента строк
 
Инкремент строки связан с диапазоном соответсвующих строк.
# $var = 'ab9';
# say ++$var;
# ac0

Инкремент тут производится в диапазоне. (aa0 .. zz9) и т.д.
aa9
ab0
..
ab9 --> текущая строка
ac0 --> строка после инкремента
ac1
..
ac9
ad0

Давайте перейдем к более интересному примеру:

# $var = 'zz9';
# say ++$var;
# aaa0

Вот так будет выглядеть часть диапазона строк ("aaa0" .. "zzz9"), который нам поможет.

zy0
..
zy9
zz0
..
zz9  -> текущая строка
aaa0 -> строка после инкремента
..
aaa9

Ошибочно думать чтот тут инкрементится каждый символ в строке.

2.4 А как же декремент (--) 

Магическое поведение не распространяется на auto_decrement (--)
Перед декрементом, он преобразует переменную в числовой контекст, поэтому:

$var = "aaa1";
say --$var;

Output: -1

2.5 Закрепление

Ну и на последок для закрепления:

my @vars = (
    "a1a",
    "012",
    "zaz",
    "1az",
);

foreach my $var (@vars) {
    say ++$var;
}

Output:
1
013
zba
2

2.7 Ресурсы

No comments:

Post a Comment