检查字符串是否为十六进制

Fal*_*gel 41 python hex

我知道最简单的方法是使用正则表达式,但我想知道是否有其他方法可以进行此检查.

我为什么需要这个?我正在编写一个Python脚本,从SIM卡读取短信(SMS).在某些情况下,十六进制消息到达,我需要为它们做一些处理,所以我需要检查收到的消息是否是十六进制.

当我发送以下短信时:

Hello world!
Run Code Online (Sandbox Code Playgroud)

我的剧本收到了

00480065006C006C006F00200077006F0072006C00640021
Run Code Online (Sandbox Code Playgroud)

但在某些情况下,我会收到正常的短信(不是十六进制).所以我需要做一个if hex控件.

我使用的是Python 2.6.5.

更新:

这个问题的原因是,(某种程度上)我发送的消息是在接收hex到运营商发送的消息(信息消息和广告)时作为普通字符串接收的.所以我决定进行检查并确保我以正确的字符串格式显示消息.

一些额外的细节:我使用华为3G调制解调器和PyHumod从SIM卡读取数据.

可能是我的最佳解决方案:

处理这种字符串的最好方法是使用a2b_hex(aka unhexlify)和utf-16 big endian encoding(如@JonasWielicki所提到的):

from binascii import unhexlify  # unhexlify is another name of a2b_hex

mystr = "00480065006C006C006F00200077006F0072006C00640021"
unhexlify(mystr).encode("utf-16-be")
>> u'Hello world!'
Run Code Online (Sandbox Code Playgroud)

Lev*_*von 71

(1)使用int()很好地为此工作,并且Python会为你做所有的检查:)

int('00480065006C006C006F00200077006F0072006C00640021', 16)
6896377547970387516320582441726837832153446723333914657L
Run Code Online (Sandbox Code Playgroud)

将工作.如果失败,您将收到ValueError例外.

简短的例子:

int('af', 16)
175

int('ah', 16)
 ...
ValueError: invalid literal for int() with base 16: 'ah'
Run Code Online (Sandbox Code Playgroud)

(2)一种替代将遍历数据,并确保所有字符落入的范围内0..9a-f/A-F.string.hexdigits('0123456789abcdefABCDEF'因为它包含)是这个有用的两个上和下壳体数字.

import string
all(c in string.hexdigits for c in s)
Run Code Online (Sandbox Code Playgroud)

将返回True或返回False您的数据在字符串中的有效性s.

简短的例子:

s = 'af'
all(c in string.hexdigits for c in s)
True

s = 'ah'
all(c in string.hexdigits for c in s)
False
Run Code Online (Sandbox Code Playgroud)

备注:

正如@ScottGriffiths在下面的评论中正确指出的那样,int()如果您的字符串0x在开头包含,则该方法将起作用,而逐字符检查将失败.另外,检查一字符比一串字符更快,但是短信息字符串很重要,除非你按顺序处理它们中的很多(很多!),在这种情况下你可以将stringhexditigs转换为一组与set(string.hexdigits).

  • 一个小小的错误是这两种方法并不完全等效(eumiro的答案也一样)。对于以“ 0x”或“ 0X”开头的字符串,将其强制转换为“ int”将成功,但其他方法将不会成功。 (2认同)

eum*_*iro 22

您可以:

  1. 测试字符串是否只包含十六进制数字(0 ... 9,A ... F)
  2. 尝试将字符串转换为整数,看看它是否失败.

这是代码:

import string
def is_hex(s):
     hex_digits = set(string.hexdigits)
     # if s is long, then it is faster to check against a set
     return all(c in hex_digits for c in s)

def is_hex(s):
    try:
        int(s, 16)
        return True
    except ValueError:
        return False
Run Code Online (Sandbox Code Playgroud)

  • @Pooya - '7890'是十进制和十六进制数,就像'1010'可以是二进制,八进制,十进制,十六进制和任何数字...... (3认同)

Jen*_*ens 15

我知道op提到了正则表达式,但我想为完整性提供这样的解决方案:

def is_hex(s):
    return re.fullmatch(r"^[0-9a-fA-F]$", s or "") is not None
Run Code Online (Sandbox Code Playgroud)

性能

为了评估这里提出的不同解决方案的性能,我使用了Python的timeit模块.输入串是随机生成的三个不同的长度,10,100,1000:

s=''.join(random.choice('0123456789abcdef') for _ in range(10))
Run Code Online (Sandbox Code Playgroud)

Levon的解决方案:

# int(s, 16)
  10: 0.257451018987922
 100: 0.40081690801889636
1000: 1.8926858339982573

# all(_ in string.hexdigits for _ in s)
  10:  1.2884491360164247
 100: 10.047717947978526
1000: 94.35805322701344
Run Code Online (Sandbox Code Playgroud)

其他答案是这两者的变体.使用正则表达式:

# re.fullmatch(r'^[0-9a-fA-F]$', s or '')
  10: 0.725040541990893
 100: 0.7184272820013575
1000: 0.7190397029917222
Run Code Online (Sandbox Code Playgroud)

因此,选择正确的解决方案取决于输入字符串的长度以及是否可以安全地处理异常.正则表达式肯定会更快地处理大字符串(并且不会抛出ValueError溢出),但它int()是较短字符串的赢家.

  • 这个答案中的结论有些错误。它应该使用 `re.fullmatch(r'[0-9a-fA-F]+', s or '')` 和 `+` 量词。如果您使用它,那么在我的测试中(在 Python 3.6 上),`int(s, 16)` 对于*所有字符串长度* 是最快的。然而,正则表达式仍然可能是更好的选择,因为 `int(s, 16)` 接受诸如 `"0x0"` 之类的字符串。 (3认同)
  • 因为完全匹配在Python 2.7中不可用,所以可以使用return return.search(r'^ [0-9A-Fa-f] + $',s)不是None。 (2认同)

小智 14

一种更简单、更简短的解决方案,基于将字符串转换为集合并检查子集(不检查“0x”前缀):

import string
def is_hex_str(s):
    return set(s).issubset(string.hexdigits)
Run Code Online (Sandbox Code Playgroud)

更多信息请参见此处