使用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中工作.
撇号格式修饰符是非标准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)
大多数这些答案都假设格式是通用的。不是。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)
一个更有用的解决方案:
$a = 12345678;
$b = reverse $a;
@c = unpack("(A3)*", $b);
$d = reverse join ',', @c;
print $d;
Run Code Online (Sandbox Code Playgroud)
输出12,345,678.
我意识到这个问题是大约 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)
这将确保它只查找以逗号(添加到前一个循环中)或小数结尾的数字。
这是一个优雅的 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)