如何在Python中有效地检查字符串是否为十六进制

Raj*_*jan 2 python python-internals

我需要检查字符串是否是十六进制。我学到了两种方法 -

1.) 循环每个字符

all(c in string.hexdigits for c in s) # Straight forward with no optimizations
Run Code Online (Sandbox Code Playgroud)

2.) 使用int ()函数检查是否有错误

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

在第一种情况下,我知道复杂度是 O(n)。但是第二个呢?那里的时间复杂度是多少?

che*_*ner 5

int(s, 16)仍然具有 O(n) 复杂度,其中n == len(s),但两者不能直接比较。int将在比 更低的级别上迭代数据all,这更快,但int也会做更多工作(它实际上必须计算 的整数值s)。

\n\n

那么哪个更快呢?您必须对两者进行分析。

\n\n
In [1]: s = "783c"\n\nIn [2]: import string\n\nIn [3]: %timeit all(c in string.hexdigits for c in s)\n800 ns \xc2\xb1 3.23 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 1000000 loops each)\n\nIn [4]: %%timeit\n   ...: try:\n   ...:   int(s, 16)\n   ...: except ValueError:\n   ...:   pass\n   ...:\n223 ns \xc2\xb1 1.8 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 1000000 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n\n

看起来内部迭代获胜。我也在 9 位字符串上进行了测试,int速度仍然快了 4 倍左右。

\n\n

但是无效字符串怎么办?

\n\n
In [8]: s = \'g\'\n\nIn [9]: %%timeit\n   ...: try:\n   ...:   int(s, 16)\n   ...: except ValueError:\n   ...:   pass\n   ...:\n1.09 \xc2\xb5s \xc2\xb1 2.62 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 1000000 loops each)\n\nIn [10]: %timeit all(c in string.hexdigits for c in s)\n580 ns \xc2\xb1 6.55 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 1000000 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在,我们基本上正在测试短路的好处与捕获异常的成本。如果错误出现在字符串的后面会发生什么?

\n\n
In [11]: s = "738ab89ffg"\n\nIn [12]: %timeit all(c in string.hexdigits for c in s)\n1.59 \xc2\xb5s \xc2\xb1 19.9 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 1000000 loops each)\n\nIn [13]: %%timeit\n    ...: try:\n    ...:   int(s, 16)\n    ...: except ValueError:\n    ...:   pass\n    ...:\n1.25 \xc2\xb5s \xc2\xb1 19.5 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 1000000 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在我们再次看到内部迭代的好处。

\n