Perl printf使用逗号作为千位分隔符

Chr*_*nat 6 perl

使用awk,我可以用逗号作为千位分隔符打印一个数字.
(export LC_ALL=en_US.UTF-8预先).

awk 'BEGIN{printf("%\047d\n", 24500)}'

24,500
Run Code Online (Sandbox Code Playgroud)

我希望使用相同的格式与Perl一起使用,但它没有:

perl -e 'printf("%\047d\n", 24500)'

%'d
Run Code Online (Sandbox Code Playgroud)

Perl Cookbook提供此解决方案:

sub commify {
    my $text = reverse $_[0];
    $text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g;
    return scalar reverse $text;
}
Run Code Online (Sandbox Code Playgroud)

但是我假设因为printf选项在awk中工作,所以它也应该在Perl中工作.

Bor*_*din 8

撇号格式修饰符是非标准POSIX扩展名.在对Perl的文档printf具有这样说这样的扩展

Perl执行自己的"sprintf"格式化:它模拟C函数sprintf(3),但除了浮点数之外不使用它,即使那时也只允许使用标准修饰符.因此,Perl无法在本地sprintf(3)中使用非标准扩展.

Number::Format模块将为您执行此操作,并从区域设置中获取其默认设置,因此尽可能便携

use strict;
use warnings 'all';
use v5.10.1;

use Number::Format 'format_number';

say format_number(24500);
Run Code Online (Sandbox Code Playgroud)

产量

24,500
Run Code Online (Sandbox Code Playgroud)

  • 但我认为,这不是标准发布的一部分. (2认同)
  • 取决于你想要的便携性. (2认同)
  • @HoldOffHunger `require 5.010` 表示“以下代码需要 Perl 5.10.0 **或更高版本**”。如果模块作者将该行更新为较新的内容,则陷入旧版本 Perl 的开发人员将无法使用该模块,即使没有充分的理由进行该限制。最新版本的 `Number::Format` 是从 2015 年开始的 - 但即使是“旧”代码今天仍然可以完美工作!(CPAN Testers Matrix)[http://matrix.cpantesters.org/?dist=Number-Format+1.75] 显示该模块在 Perl 5.10 到 5.28 上运行良好,因此无需担心。 (2认同)

bri*_*foy 6

大多数这些答案都假设格式是通用的。不是。CLDR使用 Unicode 信息来计算。如何正确本地化数字中有一个很长的线程.

CPAN 有CLDR::Number模块:

#!perl
use v5.10;
use CLDR::Number;
use open qw(:std :utf8);

my $locale = $ARGV[0] // 'en';

my @numbers = qw(
    123
    12345
    1234.56
    -90120
    );

my $cldr = CLDR::Number->new( locale => $locale );

my $decf = $cldr->decimal_formatter;

foreach my $n ( @numbers ) {
    say $decf->format($n);
    }
Run Code Online (Sandbox Code Playgroud)

以下是一些运行:

$ perl comma.pl
123
12,345
1,234.56
-90,120

$ perl comma.pl es
123
12.345
1234,56
-90.120

$ perl comma.pl bn
???
??,???
?,???.??
-??,???
Run Code Online (Sandbox Code Playgroud)

它看起来重量级,但输出是正确的,您不必允许用户更改要使用的语言环境。但是,当需要更改语言环境时,您就可以开始了。与Number::Format 相比,我也更喜欢这个,因为我可以使用与我的终端或会话的本地设置不同的语言环境,甚至可以使用多个语言环境:

#!perl
use v5.10;
use CLDR::Number;
use open qw(:std :utf8);

my @locales = qw( en pt bn );

my @numbers = qw(
    123
    12345
    1234.56
    -90120
    );


my @formatters = map {
    my $cldr = CLDR::Number->new( locale => $_ );
    my $decf = $cldr->decimal_formatter;
    [ $_, $cldr, $decf ];
    } @locales;

printf "%10s %10s %10s\n" . '=' x 32 . "\n", @locales;

foreach my $n ( @numbers ) {
    printf "%10s %10s %10s\n",
        map { $_->[-1]->format($n) } @formatters;
    }
Run Code Online (Sandbox Code Playgroud)

输出同时包含三个语言环境:

        en         pt         bn
================================
       123        123        ???
    12,345     12.345     ??,???
  1,234.56   1.234,56   ?,???.??
   -90,120    -90.120    -??,???
Run Code Online (Sandbox Code Playgroud)


syc*_*yck 5

一个更有用的解决方案:

$a = 12345678;
$b = reverse $a;
@c = unpack("(A3)*", $b);
$d = reverse join ',', @c;
print $d;
Run Code Online (Sandbox Code Playgroud)

输出12,345,678.

  • 没有`scalar`的工作:`$ d =反向连接',',解包'(A3)*',反向$ a;` (2认同)

Lau*_*ura 5

我意识到这个问题是大约 4 年前提出的,但是由于它出现在搜索中,我将添加一个我想出的优雅的原生 Perl 解决方案。我最初是在寻找一种用 sprintf 来做这件事的方法,但我发现的一切都表明它无法完成。然后因为每个人都在滚动自己的,我想我会试一试,这是我的解决方案。

$num = 12345678912345; # however many digits you want
while($num =~ s/(\d+)(\d\d\d)/$1\,$2/){};
print $num;
Run Code Online (Sandbox Code Playgroud)

结果是:

12,345,678,912,345
Run Code Online (Sandbox Code Playgroud)

说明: 正则表达式对所有前导数字进行最大数字搜索。它所作用的一行中的最小位数是 4(1 加 3)。然后它在两者之间添加一个逗号。Next 循环如果最后还有 4 个数字(在逗号之前),它将添加另一个逗号,依此类推,直到模式不匹配。

如果您需要安全使用小数点后超过 3 位的数字,请使用此修改:(注意:如果您的号码没有小数,这将不起作用)

while($num =~ s/(\d+)(\d\d\d)([.,])/$1\,$2$3/){};
Run Code Online (Sandbox Code Playgroud)

这将确保它只查找以逗号(添加到前一个循环中)或小数结尾的数字。


Y.K*_*.K. 5

这是一个优雅的 Perl 解决方案,我已经使用了 20 多年了:)

1 while $text =~ s/(.*\d)(\d\d\d)/$1\.$2/g;
Run Code Online (Sandbox Code Playgroud)

如果您想要两位小数:

$text = sprintf("%0.2f", $text);
Run Code Online (Sandbox Code Playgroud)