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

I am trying to figure out the best way to determine if a string is a valid hex number. The way that popped in my head was:
if ( $string =~ /[0-9a-fA-F]+/ ) { # valid number } else { # not valid number }

After reading input validation docs ( especially the ones concerning email address validation ) I get the feeling that there is probably a better way to do this. Any ideas?

Thanks

HiFoo

Replies are listed 'Best First'.
Re: Validating Hex Numbers
by kal (Hermit) on Jan 08, 2003 at 22:20 UTC

    That doesn't look too bad, although you might want to think along the lines of /^[0-9a-fA-F]+$/, which is "$string is a hex number", rather than "$string contains a hex number"

    Don't think so much about the e-mail validation - that's a special case, because there are so many levels on which an e-mail address could be valid (valid format for an email address, leads to a valid e-mail box, etc..)

    If you want to be rock-solid, you might want to look at the different formats people write hex numbers: I've seen 0a12 written as 0x0a12, 0A12H, and there are probably a few other variations. But, if your code above is good for the data you're processing, then it's great.

Re: Validating Hex Numbers
by bart (Canon) on Jan 08, 2003 at 22:46 UTC
    In addition to using an anchored(!) regex — but otherwise much as you wrote; you can also use the tr operator, like this:
    length $h && $h !~ tr/0-9A-Fa-f//c;
    This tests if $h doesn't contain any characters it shouldn't contain, and additionally, if there are any characters at all.
Re: Validating Hex Numbers
by ihb (Deacon) on Jan 09, 2003 at 02:35 UTC
    The solution depends a bit on your problem. If you ever plan to treat the string as a hex number in Perl then my first take on the problem would be to use Perl's own hex() function to see if Perl thinks it's a hex number or not. This routine will return false for any complaints Perl might have, like integer overflow or non-portable value.
    sub is_hex { my ($s) = @_; local $SIG{__WARN__} = sub { die }; return eval { scalar hex $s; 1 }; }
    If you don't care about if Perl thinks it's portable and/or too large to be an integer then you can make it not warn about that through the warnings pragma (no warnings 'appropriate category';, see perllexwarn) or by handling the warnings in the warn hook:
    local $SIG{__WARN__} = sub { /non-portable/i or /overflow/i or die for @_; };
    Hope I've helped,
    ihb
Re: Validating Hex Numbers
by jmcnamara (Monsignor) on Jan 08, 2003 at 23:35 UTC

    Here is one way using the POSIX strtol function:
    #!/usr/bin/perl -wl use strict; use POSIX 'strtol'; sub is_hex { local $!; return ! (POSIX::strtol($_[0], 16))[1]; } my @hex = (0x1234, 1234, "0X1234", "beetroot", "decade", "fax"); print is_hex($_), "\t", $_ for @hex; __END__ Prints: 1 4660 1 1234 1 0X1234 beetroot 1 decade fax

    --
    John.

Re: Validating Hex Numbers
by PodMaster (Abbot) on Jan 08, 2003 at 22:36 UTC
    That won't really validate the number.

    Feed it any of these non-hex strings and they'll be validated.

    qw[ afg fA lA rA 0X ]
    and the list goes on.

    You need to make sure the entire string consists of only those characters, and in order to do that, you need anchors (notice I use \z instead of $)

    /^[\da-f]+\z/i
    The other thing you might have to check is the length of the string (should be even, even though 'AFF' might be considered '0AFF', whatever).

    update: thanks sauoq for tyepo catch ;)


    MJD says you can't just make shit up and expect the computer to know what you mean, retardo!
    ** The Third rule of perl club is a statement of fact: pod is sexy.

      I would definitely *not* check the length of the string if this is intended to be a general-purpose solution. A is a perfectly valid hex number, just as 8 is a valid decimal number.

      Of course, in computing contexts single-hex-digit numbers are unusual, but the poster didn't specify what the source or destination of this data is, so I wouldn't want to build in that assumption without additional information.

      One thing that the post implies but doesn't make explicit is that "number" really means "non-negative integer". If you want to be truly comprehensive, something like -A8F.C is a valid hex number (namely -2073.75 decimal), but not something most of us likely encounter on a regular basis.

              $perlmonks{seattlejohn} = 'John Clyman';

Re: Validating Hex Numbers
by diotalevi (Canon) on Jan 08, 2003 at 22:27 UTC

    You probably meant to say $string !~ m/[^0-9a-f]/i. Here you specify the values that are ok and everything else is forbidden.

    Update Oops! I fixed the regex so that '!' became '^'. I've been reading too much VB-alike docs lately.


    Fun Fun Fun in the Fluffy Chair