-3

可能重复:
在 Perl 中使用“printf”格式化输出

my @selections = ("Hamburger","Frankfurter","French Fries","Large Coke","Medium Coke","Small Coke","Onion Rings");
my @prices = (3.49, 2.19, 1.69, 1.79, 1.59, 1.39, 1.19);
my @quantity = (3, 0, 0, 4, 0, 0, 8);

printf("%s %10s %12s %10s\n", "Qty", "Desc.", "Unit \$", "Total");

for($meh = 0; $meh <= 6; $meh++)
{
    if($quantity[$meh] != 0)
    {
        printf("%d %10s %9.2f %7.2f\n", $quantity[$meh], $selections[$meh], $prices[$meh], $prices[$meh]*$quantity[$meh])
    }
}

我不知道如何使列对齐。我遵循了另一个帖子的建议,但它仍然无法正常工作。

4

3 回答 3

2

问题是您的字符串长度超过 10 个字符,并且 Perl 不会剪切它们,除非您指定最大宽度,该宽度在字符串的点之后 ( %10.10s) 给出。此外,您可能希望使用负数,以便它们向左对齐 ( %-10.10s)。

于 2012-10-23T20:52:33.977 回答
1

很久以前,Perl 主要用于格式化文件。尽管自 Perl 4.x 出现以来我还没有看到它在程序中使用过,但它仍然具有这种功能。

查看perlform文档、format函数和write函数。

我会给你一个关于代码是什么样子的例子,除非我已经多年没有这样做了。否则,使用该printf语句。您可以使用一种格式来限制文本字段的大小%-10.10s。这表示左对齐字符串,并将其填充到 10 个字符,但不超过 10 个字符。

我还建议你买一本关于现代Perl 的书。一个会教你参考的。

我已经重写了您的程序以使用引用。请注意,所有数据现在都在一个数组中,而不是分布在您希望将索引保持在一起的四个单独的数组中。

我可以通过说来谈论主菜。它更易于阅读和维护。$item[1]$item[1]->{ENTREE}

另请注意,我已经更改了您的for循环。在你的,你必须知道你有七个项目。如果您添加了新项目,则必须更改循环。在我的,我$#menu用来获取我的菜单的最后一个索引。然后我使用(0..$#menu)自动从 0 循环到@menu数组中的最后一项。

use strict;
use warnings;
use Data::Dumper;

my @menu = (
    { ENTREE => "Hamburger",    PRICE => 3.49, QUANTITY => 3 },
    { ENTREE => "Frankfurter",  PRICE => 2.19, QUANTITY => 0 },
    { ENTREE => "French Fries", PRICE => 1.69, QUANTITY => 0 },
    { ENTREE => "Large Coke",   PRICE => 1.79, QUANTITY => 4 },
    { ENTREE => "Medium Coke",  PRICE => 1.59, QUANTITY => 0 },
    { ENTREE => "Small Coke",   PRICE => 1.39, QUANTITY => 0 },
    { ENTREE => "Onion Rings",  PRICE => 1.19, QUANTITY => 8 },
);

printf "%-3.3s %-10.10s %-6.6s %s\n\n", 'Qty', 'Desc.', 'Unit $', 'Total';

# Use $#menu to get the number of items in the array instead of knowing it's 6

foreach my $item (0..$#menu) {

    # Dereference $menu[$item] to make $menu_item a hash
    # This makes the syntax easier to read.
    my %menu_item = %{ $menu[$item] };

    if ( $menu_item{QUANTITY} ) {
        printf "%3d %-10.10s %9.2f %7.2f\n",
        $menu_item{QUANTITY}, $menu_item{ENTREE}, $menu_item{PRICE},
        $menu_item{QUANTITY} * $menu_item{PRICE};
    }
}

输出:

Qty Desc.      Unit $ Total

  3 Hamburger  3.49   10.47
  4 Large Coke 1.79    7.16
  8 Onion Ring 1.19    9.52
于 2012-10-24T00:16:43.703 回答
1

如果您希望根据动态输入数据精确对齐列,则需要对行进行两次传递。第一次通过,记录每列的最大长度。然后使用这些长度构造一个格式字符串。最后,使用该格式字符串打印每一行。

use strict;
use warnings;

my @selections = ("Hamburger","Frankfurter","French Fries","Large Coke","Medium Coke","Small Coke","Onion Rings");
my @prices = (3.49, 2.19, 1.69, 1.79, 1.59, 1.39, 1.19);
my @quantity = (3, 0, 0, 4, 0, 0, 8);

my @rows;
push @rows, ["Qty", "Desc.", "Unit \$", "Total"];

# construct table data as a two-dimensional array
for (my $meh = 0; $meh < @selections; $meh++) {
    next unless $quantity[$meh];
    push @rows, [$quantity[$meh], $selections[$meh], $prices[$meh], $prices[$meh]*$quantity[$meh]];
}

# first pass over rows: compute the maximum width for each column
my @widths;
for my $row (@rows) {
    for (my $col = 0; $col < @$row; $col++) {
        $widths[$col] = length $row->[$col] if length $row->[$col] > ($widths[$col] // 0);
    }
}

# compute the format. for this data, it works out to "%-3s %-11s %-6s %-5s\n"
my $format = join(' ', map { "%-${_}s" } @widths) . "\n";

# second pass: print each row using the format
for my $row (@rows) {
    printf $format, @$row;
}

这产生了这个输出:

Qty Desc.       Unit $ Total
3   Hamburger   3.49   10.47
4   Large Coke  1.79   7.16 
8   Onion Rings 1.19   9.52 
于 2012-10-23T22:45:28.403 回答