swl has asked for the wisdom of the Perl Monks concerning the following question:
Is there an sprintf implementation available for Perl that is independent of any numeric locale settings? i.e. where sprintf "%.2g", 3.1415926 returns 3.14 and not 3,14 on locales that use a comma as the radix character.
For context, I recently hit issues with a Gtk2 interface to an application was setting the numeric locale to match a user's settings. The application uses sprintf to reduce the numeric precision of values to use as hash keys for a simple index, which then had knock-on effects when the index keys were used numerically. There were other locale effects, but that was the main one.
That specific case is now avoided since I discovered Gtk2->disable_setlocale, and I do realise that numeric locales affect more than just sprintf, but it might still be useful to have a locale independent version.
I found nothing when checking metacpan, but there look to be external libraries that allow one to specify a locale as an argument.
Re: A locale independent sprintf?
by syphilis (Archbishop) on Jul 29, 2020 at 01:21 UTC
|
Is there an sprintf implementation available for Perl that is independent of any numeric locale settings?
Not that I know of.
The simple workaround is to write a perl sub that simply does a s/,/./ on what sprintf() returns.
Or are there additional locale settings that also need to be dealt with ?
Cheers, Rob | [reply] |
|
Thanks Rob.
I was using that strategy in my code, but it incurs sub overheads and profiling showed my uses were in a fairly hot path for large data sets. (It could also just another example of me micro-optimising, though).
| [reply] |
|
Using y/,/./, instead of s/,/./, should be faster
(see "perlperf: Search and replace or tr").
Obviously, I can't say whether it will be noticeably or usefully faster.
You may want the 'r' modifier. Here's a somewhat fudged example for demonstration purposes:
$ perl -E 'say sprintf("3,%d", 14)'
3,14
$ perl -E 'say sprintf("3,%d", 14) =~ y/,/./'
Can't modify constant item in transliteration (tr///) at -e line 1, at
+ EOF
Execution of -e aborted due to compilation errors.
$ perl -E 'say sprintf("3,%d", 14) =~ y/,/./r'
3.14
If you try this, I'd be interested in what sort of speed improvement you see.
| [reply] [d/l] [select] |
|
|
|
|
Re: A locale independent sprintf?
by salva (Canon) on Jul 29, 2020 at 08:05 UTC
|
But the locale settings should not affect sprintf unless you explicitly activate it with a use locale pragma.
If you have it activated, you can disable it just for the sprintf call as follows:
my $foo = do {
no locale;
sprintf ...
};
| [reply] [d/l] [select] |
|
Thanks. I had considered overriding the locale in a sub using setlocale, but the setlocale docs indicate that it affects things globally and is not thread safe on some systems.
However, I had not considered using no locale. I'll have to give it a test.
As for activating the locale, there is no locale-setting code in my codebase. In the original case it was caused by the Gtk2 module when it was loaded. Having now side-stepped it for Gtk2, there is always the risk it will manifest if I use some other library. I guess I will have to audit such libs before adding them as dependencies.
| [reply] [d/l] |
|
| [reply] [d/l] |
|
|
Re: A locale independent sprintf?
by bliako (Monsignor) on Jul 29, 2020 at 06:54 UTC
|
After your post I quickly checked and was relieved to find that C's sprintf has not yet been touched by the locale police. phewww. Although I found this:
For some numeric conversions a radix character ("decimal point") or
thousands' grouping character is used. The actual character used
depends on the LC_NUMERIC part of the locale. (See setlocale(3).) The
POSIX locale uses '.' as radix character, and does not have a grouping
character.
And also this, which distinguishes between %g and %'g
' For decimal conversion (i, d, u, f, F, g, G) the output is to be
grouped with thousands' grouping characters if the locale infor‐
mation indicates any.
Perhaps issue a feature request that Perl follows the same principle. You will do mankind a favour. Unless it does already?
bw, bliako
| [reply] [d/l] [select] |
|
| [reply] |
|
|