Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

So I need to do a regex match for $1,000 USD and over (up to 100,000). It can include change, so $1,000.00 to $100,000.00

The regex should also check for commas. ($1,000, $10,000, $100,000).

I searched for a cpan module, but couldn't find anything.

This is what I have come up with so far:

/^\$?(?:\d{1,3},\d\d\d|\d{4,6})\.?\d?\d?$/
Could you improve it?

Replies are listed 'Best First'.
Re: matching USD amounts
by Marshall (Canon) on Aug 31, 2009 at 05:57 UTC
    I figure that sometimes these things get overly complex to the detriment of clarity. Maybe I'm guilty below as I allowed for Australian dollars vs US dollars...

    Don't be afraid to use the Perl regex engine in a couple of lines! The speed of this thing in Perl 5.10 vs Perl 5.6 is stunning. GO FOR CLARITY first.

    So talking thru the code below: (1) process only things that are US dollars (optional), (2) there is gonna be zero or more spaces, followed by the "$" sign and some sequence of digits,commas and periods. (3)that sequence gets captured and then the commas get deleted.

    Update: If max valid dollar amount is $100,000.00 then I would enforce the 100,000 max via a numeric comparison on $number. BUT, this is actually the wrong place in the system to be checking that!

    #!/usr/bin/perl -w use strict; my @bucks = ('$1,999,003 USD ', '$1,532.33 AUS', '$1,500.11 USD'); foreach my $amount (@bucks) { next unless $amount =~ m/USD/; my ($comma_amount) = ($amount =~ /\s*\$([\d,.]+)/); print "c=$comma_amount\n"; (my $number = $comma_amount) =~ s/,//g; print "n=$number\n"; } __END__ prints: c=1,999,003 n=1999003 c=1,500.11 n=1500.11
Re: matching USD amounts
by eye (Chaplain) on Aug 31, 2009 at 04:46 UTC
    This should fulfill your requirements and enforce the 100,000 max.
    /^\$(?:100,?000(?:\.00)?|\d{1,2},?\d{3}(?:\.\d\d)?)$/
Re: matching USD amounts
by Anonymous Monk on Aug 31, 2009 at 04:35 UTC
    #!/usr/bin/perl -- use strict; use warnings; use Regexp::Assemble; my( @usd ) = ( q[$0,000.00], q[$0000], q[$999], q[$1,000], q[$1,000.00], q[$2,000], q[$9,000], q[$10,000], q[$10,00000.00], q[$100,000], q[$999,000], q[$1,000,000], q[$1,234,567,890.00], ); sub refit { my( $re ) = Regexp::Assemble->new; $re->add(shift) while @_; $re=$re->re; print "\n\n$re\n"; for my $usd ( @usd ){ no warnings 'uninitialized'; printf "[ %20s ]= %d\n", $usd, $usd =~ $re; } print '-' x 50 , "\n\n"; } refit( '^\$1,?\d\d\d(?:\.\d\d)?$', # $1,000 $1,000.00 '^\$[2-9],?\d\d\d(?:\.\d\d)?$', # $2,000 $9,000 '^\$\d\d,?\d\d\d(?:\.\d\d)?$', # $10,000 $99,000 '^\$\d\d\d,?\d\d\d(?:\.\d\d)?$', # $100,000 $999,000 '^\$\d,?(?:\d\d\d,?)+\d\d\d(?:\.\d\d)?$', # $1,000,000 $1,234,5 +67,890.00 ); refit( '^\$1,?\d\d\d(?:\.\d\d)?$', # $1,000 $1,000.00 '^\$[2-9],?\d\d\d(?:\.\d\d)?$', # $2,000 $9,000 '^\$\d\d[\d,]*?\d\d\d(?:\.\d\d)?$', # $10,000 $10,00000.00 ); __END__ (?-xism:^\$(?:\d(?:,?(?:\d\d\d,?)+|\d?\d,?)|(?:[2-9]|1),?)\d\d\d(?:\.\ +d\d)?$) [ $0,000.00 ]= 0 [ $0000 ]= 0 [ $999 ]= 0 [ $1,000 ]= 1 [ $1,000.00 ]= 1 [ $2,000 ]= 1 [ $9,000 ]= 1 [ $10,000 ]= 1 [ $10,00000.00 ]= 0 [ $100,000 ]= 1 [ $999,000 ]= 1 [ $1,000,000 ]= 1 [ $1,234,567,890.00 ]= 1 -------------------------------------------------- (?-xism:^\$(?:(?:[2-9]|1),?|\d\d[\d,]*?)\d\d\d(?:\.\d\d)?$) [ $0,000.00 ]= 0 [ $0000 ]= 0 [ $999 ]= 0 [ $1,000 ]= 1 [ $1,000.00 ]= 1 [ $2,000 ]= 1 [ $9,000 ]= 1 [ $10,000 ]= 1 [ $10,00000.00 ]= 1 [ $100,000 ]= 1 [ $999,000 ]= 1 [ $1,000,000 ]= 0 [ $1,234,567,890.00 ]= 0 --------------------------------------------------
Re: matching USD amounts
by Narveson (Chaplain) on Aug 31, 2009 at 16:48 UTC

    Use the regex engine just to locate the number. To see if the number is between a thousand and a hundred thousand, use the built-in Perl implementation of arithmetic.

    while (<>) { chomp; print "$_: "; if (my ($number) = /^\$?(\d[,\d]*)/) { $number =~ s/,//g; print $number < 1000 ? 'too small' : $number > 100_000 ? 'too big' : 'just right'; } else {print 'not a number'} print "!\n"; }
Re: matching USD amounts
by Anonymous Monk on Aug 31, 2009 at 04:11 UTC
    $re = qr! ^ \$\d [\d,]*? \d\d\d (?:\.\d\d)? $ !x;
Re: matching USD amounts
by ashish.kvarma (Monk) on Aug 31, 2009 at 13:50 UTC
    Another one liner is
    ^\$(?:(?:1\d{0,2})|(?:[1-9]\d?)),\d{3}(?:\.\d\d)?$
    This regex check for ',', value > 1,000 but < 100,000. it also checks that the value doesn't start with '0'. It might be a little complex (to read) but it works.
    Regards,
    Ashish