TheBlackCorsair
TheBlackCorsair

Reputation: 527

How to convert a string number to a real number?

I was wondering if there is a way to convert a number like

100u     10km     300nm      and so on

so that they are interpreted as:

100*10^-6      10*10^3      300*10^-6

I need to compare these numbers (100u, 10km, etc.). For example, if I want to compare 100u to 10u, that's ok; I just do the following, which is not correct but does the job:

$distance =~ s/(.*)u/$1/;
if ($distance >= $desired_distance) {
       printf $distance;
}

where (.*)u is the number, e.g. 100u. So I just remove the u and then compare it with a number.

But, what if I have the number

1.45m 

and I want to compare it with

1400u

The above thing wouldn't help.

Upvotes: 4

Views: 186

Answers (3)

toolic
toolic

Reputation: 62019

Number::FormatEng will help to convert standard prefixes into numeric values:

use warnings;
use strict;

use Number::FormatEng qw(:all);
for (qw(100u 1.45m 1400u)) {
    print "$_ ", unformat_pref($_), "\n";
}

Output:

100u 0.0001
1.45m 0.00145
1400u 0.0014

Upvotes: 12

zoul
zoul

Reputation: 104065

If there’s no CPAN module for that you can always roll your own:

my %units = (
    m  => 1,
    km => 1000,
    mm => 0.001,
);

for my $num (qw(10 10km 10mm)) {
    $num =~ /(\d+)(\w+)?/;
    my $value = $1;
    my $unit  = $2 || 'm';
    print "$num = ", $value*$units{$unit}, " m\n";
}

Which outputs:

10 = 10 m
10km = 10000 m
10mm = 0.01 m

Plus tests and error handling. See TLP’s answer for some more idiomatic expressions.

Upvotes: 7

TLP
TLP

Reputation: 67900

Just make a subroutine to normalize your input, e.g.

sub normalize {
    my %unit = (
        u  => 10^-6,
        km => 10^3,
        # etc
    );
    my $num = shift;
    my ($base, $unit) = $num =~ /(\d+)(\S+)/;
    $base *= $unit{$unit} // 1;   # default to 1 if no unit is found
    return $base;
}

Upvotes: 6

Related Questions