NEWBIE: ishexdigit revisited

engsolnom at ipns.com engsolnom at ipns.com
Tue Dec 30 01:44:34 CET 2003


On 29 Dec 2003 15:34:03 -0800, Paul Rubin
<http://phr.cx@NOSPAM.invalid> wrote:

>engsolnom at ipns.com writes:
>> After looking at the suggestions for a ishexdigit method, (thanks
>> again), I decided on the following, partly because I don't have to
>> import string, and I believe it's pretty readable by Python newbies,
>> which we (including myself) have at work:
>> 
>> def ishexdigit(sx):
>>     ix = 0
>>     for cx in sx:
>>         ix += 1
>>         if not cx in '0123456789abcdefABCDEF': return 0
>>     if ix % 2 == 0: return 1
>>     else: return 'Extra nibble'
>
>Some remarks:
>
>1) I think the name is a misnomer: "ishexdigit" should test just one
>digit, not a multi-digit string.  This function should be called
>"ishexnumber" instead.

I used 'isdigit' as a model, since it takes a string also. But
ishexnumber works for me too, except I'll usually pass long strings to
it..:)
>
>2) I'm not sure why you return 'extra nibble' if there's an odd number
>of digits.  Isn't '123' a perfectly good hex number (= 291 decimal)?
>
>3) Even if you do want to check that the length is odd, you don't
>   need to count the chars in the loop:
>
>     def ishexnumber(sx):
>         for cx in sx:
>             if not cx in '0123456789abcdefABCDEF': return 0
>         if len(sx) % 2 == 0: return 1
>         return 'Extra nibble'
>
>   (the final 'else' is not needed)

Forehead slap! "if len(sx) % 2 == 0:" makes better sense...thanks!
>
>4) You could also use a regular expression to test for hex digits:
>
>     def ishexnumber(sx):
>         import re
>         if not re.match('[0123456789abcdefABCDEF]*$', sx): return 0
>         if len(sx) % 2 == 0: return 1
>         return 'Extra nibble'
If I run this many times, as is likely in our application, does the
'import re' chew up memory?
>
>5) If you want the number of bytes to be even because the hex string
>   is supposed to represent a character string, and you're going to
>   do the conversion next, there's already a library function for that:
>
>      import binascii     
>      s = binascii.unhexlify(sx)
>

>6) If you want it to be a number but still need the digit count to
>   be even for some reason, then checking for the special value 
>   'Extra nibble' is messy.  It's usually better to raise an exception
>   instead:
>
>     def ishexnumber(sx):
>         for cx in sx:
>             if not cx in '0123456789abcdefABCDEF': return 0
>         if len(sx) % 2 != 0:
>             raise ValueError, 'Extra nibble in hex string'
>         return 1
>
>   The caller then has to catch the exception, of course.
I do need to learn more about exceptions.
>
>7) If you want to just check that the hex string represents an
>   integer, possibly the most robust way is:
>
>     def ishexnumber(sx):
>         try:
>             n = int(sx, 16)
>         except ValueError:
>             return 0
>         return 1
>
>   Note this will fail for hex strings are too long to fit in a short int.

Our strings will almost always be long ones, and the byte values will
range from zero to 255, but I'll tuck this nugget into the archive.

Thanks for the comments. 
Norm





More information about the Python-list mailing list