The C functions strtol and strtod would seem to be canonical
for this problem.  Accessible through the POSIX module, they
can handle large numbers, a wide range of representations, and
provide both domain and range error checking.

You could use a regex like /^\s*(-|\+)?0(.)/ to match binary, octal,
and hex representations but octal has an implicit base that will need to be
accounted for.  Solving for that makes the regex unnecessary.

After parsing the first few bytes to extract the sign and base into components*,
the rest falls into place:

    sub parse
        extract input into sign, base, and str_val
        convert str_val to numeric value using strto[dl]
        handle errors # See man POSIX::strto[dl] 
        negate numeric value if sign eq '-'
        return numeric value

* Extracting the sign and base will necessarily require a position variable.
Let's call it $i.  The final value for $i can be used to extract the
(absolute) numeric part of the input value with substr($str_val, $i)

In this context, eval is a red herring with a big stench.

-Gyepi

On Wed, Feb 23, 2022 at 08:31:12AM -0600, em...@greglondon.com wrote:
> Copy/pasting a regexp for checking
> would probably work in my situation.
> 
> That numpack idea is great.
> 
> It solves another issue i didnt
> even mention which is that some
> numbers can be arbitrarily huge.
> 
> If i parse one char at a time,
> I should be able to use bignum
> and still get the correct answer.
> 
> A little surprised there isnt a
> way to restrict eval to some
> particular perl grammar subrule like
> "Numeric literal". (Shrug)
> 
> Regexps will be a bit more work
> but will do the job.
> 
> Thanks everyone!
> Greg
> 
> 
> 
> On 2022-02-22 22:01, Jerrad Pierce wrote:
> > There are two things you can do:
> > 
> > a) use regular expressions on the "numbers" to see if they conform
> > to known format, and then eval iff they do; you can then bypass eval
> > for integer/float since +0 will cover it.
> > 
> >     e.g; e.g; /\s+0b[01]+\s+/
> > 
> > You should be able to crib RE from RegExp::Common, no need to install
> > and use the full module.
> > 
> > b) use regular expressions to identify the format plus some packing/
> > unpacking and code-point indexing to convert the number without eval:
> > 
> >     # binary 285, this implementation is sensitive to leading zeroes--
> >     # others may not be--and requires whole bytes. Padding is left as
> >     # an exercise for the reader
> >     $num = numpack("B*", "0000000100011101");
> > 
> >     #hex 3735928559
> >     $num = numpack("H*", "deadbeef")
> > 
> >     sub numpack {
> >     my($fmt, $val)=@_;
> >     my($i, $sum)=(1, 0);
> > 
> >     my @char =split //, unpack("a*", pack($fmt, $val));
> >     my $bytes=scalar(@char);
> >     foreach(@char){ $sum+=ord()<<(8*($bytes-$i++))}; #shift and add bytes
> >     return $sum
> >     }
> 
> _______________________________________________
> Boston-pm mailing list
> Boston-pm@pm.org
> https://mail.pm.org/mailman/listinfo/boston-pm

-- 
The shortest answer is the doing the thing.     --Author Unknown

_______________________________________________
Boston-pm mailing list
Boston-pm@pm.org
https://mail.pm.org/mailman/listinfo/boston-pm

Reply via email to