Perl регулярные выражения: замена табуляций пробелами

В пособиях по Perl регулярным выражениям встречается регулярное выражение для замены одного символа табуляции пробелами, но предположим, что нам надо заменить одним оператором подстановки все табуляции в тексте соответствующим числом пробелов. Может показаться, что достаточно каждый символ табуляции \t заменить 8-ю пробелами, и дело в шляпе, но дело обстоит сложнее: число пробелов для замены каждой табуляции зависит от положения символа \t в его строке. Текст должен выравниваться на 9-ю, 17-ю, 25-ю и т.д. позицию, как это и делают текстовые редакторы.

Попробуем обратиться к "коллективному разуму" и наберём в поиске Гугла строку замена табуляций на пробелы "регулярные выражения" перл. Сразу жа выскочит URL wdh.suncloud.ru/perl04.htm. На этой странице находим готовый рецепт нужной нам замены:
1 while s/\t+/' ' x (length($&)*8 - length($`)%8)/e;

В качестве проверки набросаем такую программку:

#!/usr/bin/perl -w
use strict;

$_=<<EOF;
Первая строка.
\t\tВторая строка.
EOF

1 while s/\t+/' ' x (length($&)*8 - length($`)%8)/e;
print $_;

Получаем результат:

Первая строка.
         Вторая строка.

Ёшь твою мышь, Тохтамыш! "Вторая строка." начинается с 10-й позиции, а должна начинаться с 17-й! Вот и доверяй после этого коллективному разуму... Не иначе, придётся использовать наш собственный, уже закипающий и возмущённый, разум. Ну, и, конечно, немного магии в виде модификатора e и кода Perl как в секции поиска, так и в секции замены:

#!/usr/bin/perl -w
use strict;

# Замена во всём тексте всех символов табуляции соответствующим числом пробелов.
# Автор Сергей Мельников. Сделано для сайта "Perl регулярные выражения, статьи вебмастеру"
# http://www.cronc.com/ru.shtml

$_=<<EOF;
a\tПервая строка\t.
Вторая строка.
\t\tТретья строка.
Четвертая строка.
EOF

my ($offs,$tmp);

s/(?:^(?{ $offs=0 }))?         # в начале каждой строки обнуляем $offs
  ([^\t\n\r]*)                 # в $1 берём все символы в строке кроме \t
  \t                           # этот знак табуляции заменим пробелами
 /$tmp=$offs+length $1;        # в $tmp - смещение от начала строки до этой табуляции +1
  $offs+=$tmp+(8-$tmp % 8);    # в $offs - к нему добавляем число пробелов для замены этого \t
  $1.' ' x (8-$tmp % 8)/egmx;  # сохраняем $1 и заменяем \t пробелами

print $_;

На печать выдаётся:

a       Первая строка   .
Вторая строка.
                  Третья строка.
Четвертая строка.

Внимательно подсчитываем позиции выравнивания и убеждаемся, что всё верно!