Reputation: 2589
I am trying to write a script to make a integer into comma separated value:
For Example Input :
23454546.3435353 test 123454546789.3435353
#'n' number of values will be present.I am receiving output:
234, 54, 546.34, 35, 353 test 123454546789.34, 35, 353
My Query is, after the decimal value do not insert
,
.Required Output :
2,34,54,546.**3435353**
test1,23,45,45,46,789.**3435353**
My Code:
my $strg = "23454546.3435353 test 123454546789.3435353"
$strg=~s#([^\.])(\d{4,})# my $no_dot=$1; my $nums = $2; my $cnt = $nums=~s/\d/$&/g;
if($cnt eq 8) { $nums=~s/^(\d{1})(\d{2})(\d{2})(\d{3})$/$1\, $2\, $3\, $4/g; }
if($cnt eq 7) { $nums=~s/^(\d{2})(\d{2})(\d{3})$/$1\, $2\, $3/g; }
if($cnt eq 6) { $nums=~s/^(\d{1})(\d{2})(\d{3})$/$1\, $2\, $3/g; }
if($cnt eq 5) { $nums=~s/^(\d{2})(\d{3})$/$1\, $2/g; }
if($cnt eq 4) { $nums=~s/^(\d{1})(\d{3})$/$1\, $2/g; }
($no_dot.$nums);
#ge;
Please advice where I am doing wrong.
Upvotes: 2
Views: 389
Reputation: 16807
Your detection of relevant strings is flawed. You have:
([^\.])(\d{4,})
but this means the first character can be a digit.
That explains why you get 234,
in your output.
It will also match the digits one beyond a period (so in .3435353
, you match 3435353
). Note that the \
is not needed (.
is not special inside square brackets).
Try this:
$strg =~ s{
( # $1:
( ^ | \s ) # delimiter (whitespace or line start)
\d{4,} # digits that need commas
)
(?= # lookahead:
( \. \d+ )? # optional fractional part
( \s | $ ) # delimiter (whitespace or line end)
)
}{
local $_ = $1;
s/(\d)(?=(\d{2})*\d{3}$)/$1,/g;
$_;
}xeg;
The outer regex matches runs of 4 or more digits (optionally followed by a fractional part), delimited either by whitespace or at the start/end of the string.
The inner regex also makes use of lookahead to find digits that need commas (ie. 2n+4 from the right). Because of greedy matching of the lookahead, replacements are made starting from the left.
Upvotes: 1
Reputation: 40778
Maybe easier to use Locale::Currency::Format ?
use Locale::Currency::Format;
my $inr = currency_format('INR', 23454546.3435353);
say $inr;
Output:
23,454,546.34 INR
Edit:
It seems like the precision cannot be modified by the module. If you want a precision other than 2, you can try use the brute force approach. For example:
my $strg = "23454546.3435353 test 123454546789.3435353";
$strg =~ s/(\d+)\.(\d+)/do_subst($1,$2)/ge;
sub do_subst {
my ($p1, $p2) = @_;
my $temp = reverse $p1;
my @parts;
push @parts, $1 if $temp =~ s/^(\d{1,3})//;
while (length $temp) {
push @parts, $1, if $temp =~ s/^(\d{1,2})//;
}
return (join ',', map {my $p = reverse $_; $p} reverse @parts) . '.' . $p2;
}
say $strg;
Output:
2,34,54,546.3435353 test 1,23,45,45,46,789.3435353
Upvotes: 3