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 Первая строка . Вторая строка. Третья строка. Четвертая строка.
Внимательно подсчитываем позиции выравнивания и убеждаемся, что всё верно!