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

Esteemed Monks,

I need to figure out if a given number is larger than a specific floating point number format. For example, given a FPN with a precision of 4 and a scale of 3, they must be in the format of something like X.XXX, but needn't have all of those numbers. So 1 is valid, .45 is valid, 3.452 is valid, but 12.3 is not valid, nor is .34567.

I know there are other ways to do this, but I'd just assume use a regex if I can. I know how to look for specific numbers of certain chars using braces, but how do I look for n or less characters? I could run it through a filter first to pad the right and left sides with zeros before running it through something like:

$float =~ /\A\d\.\d{3}\z/;

but I'd just assume do it all in one fell swoop. Negative numbers and exponents are edge cases that I'm not concerned about in this case.

Replies are listed 'Best First'.
Re: Regex for max length float
by Sidhekin (Priest) on Mar 14, 2007 at 14:55 UTC

    I'm not sure what you mean with "precision" (why isn't "12.3" valid?), but judging by your examples, and assuming your "number" really is a string, I come up with this:

    $float =~ /\A(?:\d|\d?\.\d{1,3})\z/;

    print "Just another Perl ${\(trickster and hacker)},"
    The Sidhekin proves Sidhe did it!

      Of course! I forgot that braces are inherently range operators, so this should actually do the trick for me:

      $max_lhs = $precision - $scale; $max_rhs = $scale; $float =~ m/ \A # beggining of string \d{0,$max_lhs} # 0 to $max_lhs digits \. # decimal point \d{0,$max_rhs} # 0 to $max_rhs digits \z # end of string /xms;

      I know the notion of what I'm calling 'precision' is confusing. I'm actually trying to check for the format of floats before inserting them into an Oracle number field and that's what Oracle calls them:

      precision - total number of digits
      scale - digits on the rhs

        If you say in your OP that 1 is valid then your regex will fail for that value because it expects to find a decimal point. Perhaps \.? making it optional would be better?

        Cheers,

        JohnGG

        I'm confused. You say:

        precision - total number of digits
        scale - digits on the rhs

        but in you OP, you say that:

        with a precision of 4 and a scale of 3 (...) 12.3 is not valid

        Why not? Its total number of digits (3) is less than 'precision', and there is only one digiit on the rhs...

Re: Regex for max length float
by kyle (Abbot) on Mar 14, 2007 at 15:19 UTC

    how do I look for n or less characters?

    You want /\d{0,3}/ (three digits or less)?

    $x = '1234'; print $x =~ /^\d{0,3}$/ ? "'$x' matches\n" : "'$x' no match\n"; $x = '123'; print $x =~ /^\d{0,3}$/ ? "'$x' matches\n" : "'$x' no match\n"; $x = '12'; print $x =~ /^\d{0,3}$/ ? "'$x' matches\n" : "'$x' no match\n"; $x = '1'; print $x =~ /^\d{0,3}$/ ? "'$x' matches\n" : "'$x' no match\n"; $x = ''; print $x =~ /^\d{0,3}$/ ? "'$x' matches\n" : "'$x' no match\n"; __END__ '1234' no match '123' matches '12' matches '1' matches '' matches

    I wonder if Regexp::Common::number would help you.

Re: Regex for max length float
by whereiskurt (Friar) on Mar 14, 2007 at 15:32 UTC

    This might get the creative juices flowing. It does output as you'd expect, but there is a limitation in this sample. Namely, the '$predec' is empty and the '$postdec' is full when there is no decimal point in the number. Anyhow... just wanted to do something fun before lunch. If I was a REGEX guru (I'm not even close to that planet) I would think that a look-ahead/behind would be useful in this case.

    Be kind, this is my first code post. :)

    KPH
    use strict; use warnings; my $precision = 4; my $scale = 3; my $regex = qr{\A(\d*?)\.?(\d*?)\z}; foreach my $float ("1", ".45", "3.452", "3.4526", "12.3", ".34567", "N +aN") { if (my ($predec,$postdec) = ($float =~ m/$regex/)) { if (length "$postdec" > $scale) { print "Invalid scale in $float ($predec\t$post +dec)\n"; } elsif (length "$predec" > $precision - $scale) { print "Invalid precision in $float ($predec\t +$postdec)\n"; } else { print "Valid number: $float ($predec\t$postdec +)\n"; } } else { print "Invalid floating point number: $float\n"; } }