Использование функции sprintf для вывода денежных суммФункция sprintf часто применяется для форматирования чисел с определенным количеством знаков в дробной части. Например, денежные суммы должны выводиться в виде 2.50, но не 2.5 – и конечно, не 2.49997! Задача легко решается при помощи формата "%.2f":my $money = sprintf "%.2f", 2.49997; При округлении чисел необходимо учитывать множество тонкостей, но в большинстве случаев числа могут храниться в памяти с максимальной точностью, а округляется только вывод. Если выводимое число достаточно велико, для разделения разрядов запятыми (например, если это денежная сумма) можно создать удобную пользовательскую функцию: sub big_money { my $number = sprintf "%.2f", shift @_; # При каждой итерации цикла добавляется одна запятая 1 while $number =~ s/^(-?\d+)(\d\d\d)/$1,$2/; # Добавляем знак доллара в нужную позицию $number =~ s/^(-?)/$1\$/; $number; } В этой функции используются некоторые возможности, которые мы еще не рассматривали, но они логически следуют из того, что было показано ранее. Первая строка функции форматирует первый (и единственный) параметр так, чтобы он содержал ровно две цифры в дробной части. while ($number =~ s/^(-?\d+)(\d\d\d)/$1,$2/) { 1; } Что здесь происходит? Тело цикла выполняется, пока замена возвращает истинное значение (признак успешного выполнения). Но тело цикла не делает ничего! Для Perl это вполне допустимо, а нам эта запись сообщает, что целью этой команды является выполнение условия (замена), а не бесполезное тело цикла. Значение 1 традиционно используется как условный заполнитель, хотя подойдет и любое другое значение. Следующая запись работает точно так же, как и приведенный ранее цикл: 'keep looping' while $number =~ s/^(-?\d+)(\d\d\d)/$1,$2/; Итак, теперь мы знаем, что цикл создан для выполнения замены. Но что делает замена? Напоминаем, что $number на этой стадии содержит строку вида "12345678.90". Шаблон совпадает с первой частью строки, но не может пройти дальше точки. (А вы видите, почему не может?) В переменную $1 заносится значение "12345", а в переменную $2 – значение "678", так что замена преобразует $number в "12345,678.90" (еще раз: совпадение для точки не находится, поэтому завершающая часть строки остается без изменений). Предыдущая попытка замены была успешной, поэтому происходит очередная итерация цикла. Но на этот раз шаблон не совпадает, потому что в начале строки должно быть не менее четырех цифр; на этом цикл завершается. Почему мы не могли воспользоваться модификатором /g, чтобы выполнить глобальный поиск с заменой и избавиться от хлопот с 1 while? Это невозможно, так как мы перемещаемся назад от точки, а не вперед от начала строки. Расставить запятые в таких числах одной лишь подстановкой s///g невозможно. Кстати, вы поняли, зачем нужен дефис? Знак «-» в начале строки – это необязательный префикс. Он присутствует и в следующей строке, где знак $ выводится в нужной позиции, так что $number принимает вид "$12,345,678.90" (или, возможно, "–$12,345,678.90", если число отрицательное). Обратите внимание: знак доллара не всегда является первым символом в строке (хотя это бы значительно упростило ее). Наконец, последняя строка возвращает отформатированную «денежную сумму» для вывода в ежегодном отчете. Статьи из раздела Perl на эту тему: ![]() ![]() ![]() ![]() ![]() Вернуться в раздел: Perl / 13. Строки и сортировка
|