Check if a string is hexadecimal

Viewed 131862

I know the easiest way is using a regular expression, but I wonder if there are other ways to do this check.

Why do I need this? I am writing a Python script that reads text messages (SMS) from a SIM card. In some situations, hex messages arrives and I need to do some processing for them, so I need to check if a received message is hexadecimal.

When I send following SMS:

Hello world!

And my script receives

00480065006C006C006F00200077006F0072006C00640021

But in some situations, I receive normal text messages (not hex). So I need to do a if hex control.

I am using Python 2.6.5.

UPDATE:

The reason of that problem is, (somehow) messages I sent are received as hex while messages sent by operator (info messages and ads.) are received as a normal string. So I decided to make a check and ensure that I have the message in the correct string format.

Some extra details: I am using a Huawei 3G modem and PyHumod to read data from the SIM card.

Possible best solution to my situation:

The best way to handle such strings is using a2b_hex (a.k.a. unhexlify) and utf-16 big endian encoding (as @JonasWielicki mentioned):

from binascii import unhexlify  # unhexlify is another name of a2b_hex

mystr = "00480065006C006C006F00200077006F0072006C00640021"
unhexlify(mystr).encode("utf-16-be")
>> u'Hello world!'
13 Answers

One more simple and short solution based on transformation of string to set and checking for subset (doesn't check for '0x' prefix):

import string
def is_hex_str(s):
    return set(s).issubset(string.hexdigits)

More information here.

Since all the regular expression above took about the same amount of time, I would guess that most of the time was related to converting the string to a regular expression. Below is the data I got when pre-compiling the regular expression.

int_hex  
0.000800 ms 10  
0.001300 ms 100  
0.008200 ms 1000  

all_hex  
0.003500 ms 10  
0.015200 ms 100  
0.112000 ms 1000  

fullmatch_hex  
0.001800 ms 10  
0.001200 ms 100  
0.005500 ms 1000

Simple solution in case you need a pattern to validate prefixed hex or binary along with decimal

\b(0x[\da-fA-F]+|[\d]+|0b[01]+)\b

Sample: https://regex101.com/r/cN4yW7/14

Then doing int('0x00480065006C006C006F00200077006F0072006C00640021', 0) in python gives 6896377547970387516320582441726837832153446723333914657

The base 0 invokes prefix guessing behaviour. This has saved me a lot of hassle. Hope it helps!

Most of the solution are not properly in checking string with prefix 0x

>>> is_hex_string("0xaaa")  
False  
>>> is_hex_string("0x123")  
False  
>>> is_hex_string("0xfff")  
False  
>>> is_hex_string("fff")  
True  

Here's my solution:

def to_decimal(s):
    '''input should be int10 or hex'''
    isString = isinstance(s, str)
    if isString:
        isHex = all(c in string.hexdigits + 'xX' for c in s)
        return int(s, 16) if isHex else int(s)
    else:
        return int(hex(s), 16)

a = to_decimal(12)
b = to_decimal(0x10)
c = to_decimal('12')
d = to_decimal('0x10')
print(a, b, c, d)
Related