ssr1012
ssr1012

Reputation: 2589

Insert comma (INR value) in numeric values - Perl

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** test 1,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

Answers (2)

jhnc
jhnc

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

Håkon Hægland
Håkon Hægland

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

Related Questions