The locale’s thousands separator

Perl can use the thousands separator appropriate for your locale, as well as the appropriate decimal separator. The Number::Format from CPAN can do all sorts of interesting localizations, but POSIX can do it.

I debated offering an example in Learning Perl (7th Edition), but POSIX‘s localeconv function returns a hash reference. And, although I’ve added an appendix covering experimental features, I didn’t want to go through enough Perl to explain slices and postfix dereferencing.

Before I get to the Perl, there are a few tips. The locale command with no arguments shows you what you have set so far:

$ locale
LANG="en_US.UTF-8"
LC_COLLATE="de_DE.UTF-8"
LC_CTYPE="de_DE.UTF-8"
LC_MESSAGES="de_DE.UTF-8"
LC_MONETARY="de_DE.UTF-8"
LC_NUMERIC="de_DE.UTF-8"
LC_TIME="de_DE.UTF-8"
LC_ALL="de_DE.UTF-8"

The locale command with -a shows you what you have installed on your system. The locale is really groups of files (maybe in /usr/share/locale) that have settings for various things, such as the monetary thousands and decimal separators.

I can get these settings POSIX‘s localeconv, which returns a hash reference. Note that if you haven’t completely set your locale, some of the keys may be missing.

use v5.22;

use feature qw(postderef);
no warnings qw(experimental);

use POSIX qw(locale_h);

# returns a hash reference, which we don't cover in Learning Perl
# LC_NUMERIC should be set. For instance:
# 	% export LC_ALL=de_DE.UTF-8
my $hash = localeconv();

# Reading about locales can help
# http://lh.2xlibre.net/locales/
my( $thousands, $decimal ) =
	$hash->@{qw(mon_thousands_sep mon_decimal_point)};

# set some defaults if the locale did not set them
$thousands //= ',';
$decimal   //= '.';

# treat the number as a string
my $number = join $decimal, 123456789, 1234;
1 while ($number =~ s/^(-?\d+)(\d\d\d)/$1$thousands$2/);

say "Number is $number";

When I run this under different locales, the output is a bit different:

$ LC_ALL=en_US.UTF-8 perl5.22.0 test.pl
Number is 123,456,789.1234

$ LC_ALL=de_DE.UTF-8 perl5.22.0 test.pl
Number is 123.456.789,1234
Leave a comment

1 Comments.

  1. Be careful – not all locals separate every three digits. For instance, India (at least English language locales there). There, 1,000,000 is apparently written 10,00,000 .

    Fortunately, CPAN can help. 🙂 See CLDR::Number

    #!/usr/bin/env perl

    use v5.10;
    use CLDR::Number;

    my $cldr = CLDR::Number->new(locale => 'en-in');
    my $decf = $cldr->decimal_formatter;

    say $decf->format(1_000_000);


    perl:~$ perl test.pl
    10,00,000

Leave a Reply

Your email address will not be published. Required fields are marked *