Rico
Rico

Reputation: 6042

Evaluate a Perl String to zero for numbers only

I have a situation where I expect variables to be passed to me as strings or numbers.

i.e.

sub foo {
    # These can be either strings or numbers
    my ($bar, $var, $star) = @_;

    # I need to check to see if $bar is the number 0 (zero)
    if ($bar == 0) {
        # Do super magic with it
    }
}

Unfortunately Perl tries to do the super magic on $bar when it contains a string.

How can I tell Perl to do super magic on $bar if and only if it is the number 0 (zero)?

I understand Perl fundamentally interprets based on context, which is the underlying problem here. A possible solution to this problem is to use regex, which is fine, but I wanted to know if there was another more "straight-forward" solution.

Thanks in advance.

Upvotes: 1

Views: 279

Answers (4)

darch
darch

Reputation: 4311

Between looks_like_number and numerical comparisons, you can get quite good results quite easily:

use Scalar::Util qw(looks_like_number);
use Test::More tests => 7;

sub is_numerically_zero {
    my ($string) = @_;

    return (looks_like_number($string) and $string == 0);
}

for my $string (qw(0 0.0 0e0), '  0  ') {
    ok(is_numerically_zero($string));
}

for my $string (qw(duckies 123), '') {
    ok(not is_numerically_zero($string));
}

This assumes you don't want to just match the literal string '0'.

Upvotes: 0

ikegami
ikegami

Reputation: 385829

It depends on what you mean by "number 0". Obviously, you include the one character string 0 is zero. But what you about three character string 0.0?

If you just want to match the one character string 0, use

if ($bar eq '0') {
   ...
}

If you want to match what Perl considers number zero, use

use Scalar::Util qw( looks_like_number );

if (looks_like_number($bar) && $bar == 0) {
   ...
}

Upvotes: 2

simbabque
simbabque

Reputation: 54333

I'd personally go with what @Disco3's comment said.

if ($bar eq 0) { ... }

This works for $bar = 0, $bar = 'foo' and $bar = 123 giving the expected result.

Here's a fun fact, though:

use Benchmark qw(cmpthese);
my $bar = '0';

cmpthese(-1, {
  'quoted'    => sub { $bar eq '0'    },
  'unquoted'  => sub { $bar eq 0      },
  'regex'     => sub { $bar =~ m/^0$/ },
});

Benchmarking these three solutions tells us that the unquoted 0 is the fastest way to do it.

               Rate    regex   quoted unquoted
regex     4504851/s       --     -70%     -76%
quoted   15199885/s     237%       --     -19%
unquoted 18828298/s     318%      24%       --

Upvotes: 4

JRFerguson
JRFerguson

Reputation: 7516

Why not:

if ( $bar =~ m/^0$/ ) {

Upvotes: 2

Related Questions