2015-12-14 2 views
4

У меня есть случайное число от 0,001 до 1000, и мне нужен perl для печати с фиксированной шириной столбца 5 символов. То есть, если он слишком длинный, он должен быть округлен, и если он слишком короткий, он должен быть дополнен пробелами.Исправлено число строк в столбце

Все, что я нашел в Интернете, предлагая использовать sprintf, но sprintf игнорирует ширину поля, если число слишком велико.

Есть ли способ получить perl для этого?

Что не работает:

my $number = 0.001 + rand(1000); 
my $formattednumber = sprintf("%5f", $number); 
print <<EOF; 
    $formattednumber 

EOF 
+2

Вы должны убедиться, что ваш пример скомпилирован. Не печатайте код в редакторе переполнения стека. Скопируйте и вставьте код _actual real_. – simbabque

+0

@simbabque исправил это, не скопировал пасту, потому что другой материал в коде просто отвлек бы внимание от проблемы – fifaltra

+0

Проблема заключалась в отсутствии котировок. Просто использование 'printf' вместо нескольких строк сделало бы лучше [mcve]. :) – simbabque

ответ

4

Вы должны определить свой sprintf шаблон динамически. Количество десятичных знаков зависит от количества цифр в левой части десятичной точки.

Эта функция сделает это за вас.

use strict; 
use warnings 'all'; 
use feature 'say'; 

sub round_to_col { 
    my ($number, $width) = @_; 

    my $width_int = length int $number; 
    return sprintf(
     sprintf('%%%d.%df', $width_int, $width - 1 - $width_int), 
     $number 
    ); 
} 

my $number = 0.001 + rand(1000); 
say round_to_col($number, 5); 

Выход может быть:

11.18 
430.7 
0.842 
+0

Мне пришлось заменить 5 на 4, чтобы сделать место для десятичной точки, и вы, вероятно, хотели записать $ width в этом месте, поэтому я ставлю $ width -1, где теперь 5, но с этим он отлично работает , благодаря. – fifaltra

+0

@fifaltra правый, я исправил это. Благодарю. Итак, теперь вы можете перейти в '5' и дать 1 + point + 3, 2 + point + 2 и так далее. Хорошая работа. – simbabque

1

Вы можете использовать pack после sprintf. Это не может быть вычислительно эффективный подход, но он относительно прост в реализации и обслуживании:

my $formattednumber = pack ('A5', sprintf("%5f", $number)); 
+0

Это не будет округлено по мере необходимости. Он просто отбивает. Я думал об использовании внешнего 'sprintf '% .5s'' изначально, но он также отрубал бы десятичные знаки. Например. для '$ number = 661.887709350259' выход должен быть' 661.9', но этот подход, а также упомянутый выше 'sprintf' будут давать' 661.8', который не округляется до десятичной. – simbabque

+1

Вы правы. Я сделал очень поспешную работу по чтению вопроса - это плохо. Спасибо за благотворительную критику. – Hambone

+0

Хм, я пробовал читать на 'pack' на perldoc.perl.org, но я до сих пор не понимаю, что здесь делает. Он просто отключается после первых пяти символов? (На самом деле я не возражаю против не округления, я сказал в вопросе, но поскольку мы имеем дело со случайными числами, так или иначе, это не так важно) – fifaltra

0

Ответ отправленный simbabque не покрывает все случаи, так что это мой улучшенный вариант, только в случае, если кто также нуждается что-то вроде этого:

sub round_to_col { 
    my ($number, $width) = @_; 

    my $width_int = length int $number; 
    my $sprintf; 
    print "round_to_col error: number longer than width" if $width_int > $width; 
    $sprintf = "%d" if $width_int == $width; 
    $sprintf = "% d" if $width_int == $width - 1; 
    $sprintf = sprintf('%%%d.%df', $width_int, $width - 1 - $width_int) 
    if $width_int < $width -1; 
    return sprintf($sprintf , $number); 
} 
Смежные вопросы