Как я могу включить переменную в выражение Perl printf? - PullRequest
7 голосов
/ 17 февраля 2010

Как включить переменную в выражение printf?

Вот мой пример:

printf "%${cols}s", $_;

Где $cols - количество столбцов и $_ является строкой.

Оператор выдает предупреждение "Недопустимое преобразование".

Проблема закончилась тем, что я забыл сжать переменную. Гах. Спасибо всем.

Ответы [ 6 ]

11 голосов
/ 18 февраля 2010

Ваша интерполированная переменная $cols выглядит так, как будто она должна быть числом, скажем, 10, поэтому

"%${cols}s"

должно интерполироваться и быть эквивалентным

"%10s"

, которая является допустимой строкой формата.

Если бы $cols было чем-то другим , чем число или допустимая строка формата, вы получите предупреждение.

Например, если:

$cols = "w";

, что приведет к "%ws" в качестве строки формата - с ошибкой, которую вы цитируете:

Invalid conversion in printf: "%w"

Информация о правильном формате может быть найдена здесь .

9 голосов
/ 18 февраля 2010

Я разобрался с вашей конкретной проблемой. Ваш код правильный. Тем не менее, я предполагаю, что $cols может быть числом, считанным из пользовательского ввода, скажем так:

my $cols = <STDIN>;

Это работает, и в числовом контексте $cols будет казаться числом, но проблема в том, что $cols не появляется в числовом контексте здесь. Это в строковом контексте, что означает, что вместо расширения до "%5s" ваша строка формата расширяется до "%5\ns". Новая строка там портит строку формата.

Измените код, где вы читаете $cols на этот:

chomp(my $cols = <STDIN>);

См. Документацию по chomp, так как вы можете использовать ее и для других входных данных.

6 голосов
/ 18 февраля 2010

Всегда используйте * в вашем спецификаторе формата, чтобы однозначно указать переменную ширину! Это похоже на совет использовать printf "%s", $str вместо printf $str.

Из документации perlfunc по sprintf:

(минимальная) ширина

Аргументы обычно форматируются так, чтобы быть настолько широкими, насколько требуется для отображения заданного значения. Вы можете переопределить ширину, указав здесь число, или получить ширину из следующего аргумента (с помощью *) или из указанного аргумента (например, с помощью *2$):

printf '<%s>', "a";       # prints "<a>"
printf '<%6s>', "a";      # prints "<     a>"
printf '<%*s>', 6, "a";   # prints "<     a>"
printf '<%*2$s>', "a", 6; # prints "<     a>"
printf '<%2s>', "long";   # prints "<long>" (does not truncate)

Если ширина поля, полученная с помощью *, отрицательна, это имеет тот же эффект, что и флаг -: выравнивание по левому краю.

Например:

#! /usr/bin/perl

use warnings;
use strict;

my $cols = 10;
$_ = "foo!";
printf "%*s\n", $cols, $_;
print "0123456789\n";

Выход:

      foo!
0123456789

При включенной прагме warnings вы увидите предупреждения для нечисловых аргументов ширины.

3 голосов
/ 18 февраля 2010

Ваш текущий метод должен работать

perl -e'my $cols=500; $_="foo"; printf "%${cols}s\n\n", $_;'
1 голос
/ 18 февраля 2010

Я не могу воспроизвести вашу проблему. Следующий код работает нормально:

use strict;
use warnings;

my $cols=40;
while (<>) {
    printf "%${cols}s\n", $_;
}

Печатает любую строку ввода, используя не менее 40 столбцов ширины.

1 голос
/ 18 февраля 2010

Мне кажется, что работает следующее:

#!/bin/perl5.8 -w
use strict;
my $cols = 5;
my $a = "3";
printf "%${cols}d\n", $a;

выходы

28$ ./test.pl
    3

29$ 
...