Comming from this answer to Format currency in Bash
, I wonder for ways to determine which characters are used as numeric separators.
There are lot of issue regarding locales and number formating, for sample:
printf '%.5f\n' $(bc -l <<<'4*a(1)')
3.14159
LANG=de_DE printf '%.5f\n' $(bc -l <<<'4*a(1)')
bash: printf: 3.14159265358979323844: invalid number
3,00000
binary calculator bc
seem not handling locale correctly...
Under mentioned answer, searching for decimal separator (or radix character), I've used this:
int2amount() {
local TIMEFORMAT=%U _decsep
read _decsep < <(eval 'time true' 2>&1)
_decsep=${_decsep//[0-9]}
...
}
This work fine:
pi() { local TIMEFORMAT=%U _decsep;read _decsep < <(eval 'time true' 2>&1);_decsep=${_decsep//[0-9]};
local pi=$(bc -l <<<'4*a(1)')
printf '%.5f\n' ${pi/./$_decsep}
}
pi
3.14159
LANG=de_DE pi
3,14159
But as thousand separator is a lot easier to find:
printf -v ts "%'d" 1111 ; ts=${ts//1}
There is no fork, so system footprint is very light.
So I could imagine at begin of source file, something like:
numericSeparators() {
local TIMEFORMAT=%U
read NUM_DEC_SEP < <(eval 'time true' 2>&1)
NUM_DEC_SEP=${NUM_DEC_SEP//[0-9]}
printf -v NUM_THO_SEP "%'d" 1111
NUM_THO_SEP=${NUM_THO_SEP//1}
}
numericSeparators
declare -r NUM_THO_SEP NUM_DEC_SEP
...
But I think <(eval 'time true' 2>&1)
heavy for the goal. I'm searching for a lighter and/or cleaner way for determine them (even both decimal and thousand separators).
Thanks to dan's answer, my function would become simplier and quicker!
numericSeparators() {
local numtest
printf -v numtest "%'.1f" 1111
NUM_THO_SEP=${numtest:1:1}
NUM_THO_SEP=${NUM_THO_SEP/1}
NUM_DEC_SEP=${numtest: -2:1}
}
numericSeparators
for loctest in C en_US.UTF-8 de_DE.UTF-8 ;do
LANG=$loctest numericSeparators
printf ' %-12s thousand: \47%s\47 decimal: \47%s\47\n' \
"$loctest" "$NUM_DEC_SEP" "$NUM_THO_SEP"
done
C thousand: '.' decimal: ''
en_US.UTF-8 thousand: '.' decimal: ','
de_DE.UTF-8 thousand: ',' decimal: '.'
CodePudding user response:
You can get the locale's radix character (decimal separator) with:
printf -v ds '%#.1f' 1
ds=${ds//[0-9]}
And the thousands grouping separator, with:
printf -v ts "%'d" 1111
ts=${ts//1}
Some locales (eg. C
) have no thousands separator, in which case $ts
is empty. Conversely, if the radix character is not defined by the locale, POSIX (printf(3)
) says it should default to .
. The #
flag guarantees that it will be printed.