【发布时间】:2025-12-06 06:55:02
【问题描述】:
给定字符串(或任何长度为偶数对的字符串): "12345678"
如何交换相邻的“单词”?
我想要的结果是 "34127856"
此外,完成后我需要交换多头。 我想要的结果是: "78563412"
【问题讨论】:
-
如果字符串是 "123456789012" ,输出应该是什么?
给定字符串(或任何长度为偶数对的字符串): "12345678"
如何交换相邻的“单词”?
我想要的结果是 "34127856"
此外,完成后我需要交换多头。 我想要的结果是: "78563412"
【问题讨论】:
我正在使用以下方法:
data = "deadbeef"
if len(data) == 4: #2 bytes, 4 characters
value = socket.ntohs(int(data, 16))
elif len(data) >= 8:
value = socket.ntohl(int(data, 16))
else:
value = int(data, 16)
为我工作!
【讨论】:
正则表达式方法:
import re
twopairs = re.compile(r'(..)(..)')
stringwithswappedwords = twopairs.sub(r'\2\1', basestring)
twoquads = re.compile(r'(....)(....)')
stringwithswappedlongs = twoquads.sub(r'\2\1', stringwithswappedwords)
编辑:
然而,这绝对不是 Python 中最快的方法——以下是人们发现这些事情的方法:首先,将所有“竞争”方法写入一个模块,这里我称之为'swa.py'...:
import re
twopairs = re.compile(r'(..)(..)')
twoquads = re.compile(r'(....)(....)')
def withre(basestring, twopairs=twopairs, twoquads=twoquads):
stringwithswappedwords = twopairs.sub(r'\2\1', basestring)
return twoquads.sub(r'\2\1', stringwithswappedwords)
def withoutre(basestring):
asalist = list(basestring)
asalist.reverse()
for i in range(0, len(asalist), 2):
asalist[i+1], asalist[i] = asalist[i], asalist[i+1]
return ''.join(asalist)
s = '12345678'
print withre(s)
print withoutre(s)
请注意,我设置了s 并尝试了这两种方法来快速检查它们实际上计算的是相同的结果——一般来说,对于这种“面对面的性能竞赛”来说,这是一种很好的做法!
然后,在 shell 提示符下,使用timeit,如下所示:
$ python -mtimeit -s'import swa' 'swa.withre(swa.s)'
78563412
78563412
10000 loops, best of 3: 42.2 usec per loop
$ python -mtimeit -s'import swa' 'swa.withoutre(swa.s)'
78563412
78563412
100000 loops, best of 3: 9.84 usec per loop
...您发现在这种情况下,无 RE 的方法快了大约 4 倍,这是值得优化的。一旦有了这样的“测量工具”,当然,如果在此操作中需要“真正超快的速度”,也很容易尝试进一步的替代方案和调整以进一步优化。
编辑:例如,这是一种更快的方法(添加到相同的swa.py,当然最后一行是print faster(s);-):
def faster(basestring):
asal = [basestring[i:i+2]
for i in range(0, len(basestring), 2)]
asal.reverse()
return ''.join(asal)
这给出了:
$ python -mtimeit -s'import swa' 'swa.faster(swa.s)'
78563412
78563412
78563412
100000 loops, best of 3: 5.58 usec per loop
大约 5.6 微秒,低于最简单的无 RE 方法的大约 9.8 微秒,是另一个可能值得的微优化。
当然,等等——有一个古老的(伪)定理说,任何程序都可以缩短至少一个字节,至少快一纳秒......;-)
编辑:为了“证明”伪定理,这里有一个完全不同的方法(替换 swa.py 的结尾)...:
import array
def witharray(basestring):
a2 = array.array('H', basestring)
a2.reverse()
return a2.tostring()
s = '12345678'
# print withre(s)
# print withoutre(s)
print faster(s)
print witharray(s)
这给出了:
$ python -mtimeit -s'import swa' 'swa.witharray(swa.s)'
78563412
78563412
100000 loops, best of 3: 3.01 usec per loop
为了进一步可能值得加速。
【讨论】:
只针对字符串“12345678”
from textwrap import wrap
s="12345678"
t=wrap(s,len(s)/2)
a,b=wrap(t[0],len(t[0])/2)
c,d=wrap(t[1],len(t[1])/2)
a,b=b,a
c,d=d,c
print a+b+c+d
你可以把它变成一个泛型函数来做变长字符串。
输出
$ ./python.py
34127856
【讨论】:
如果您想进行字节序转换,请在原始二进制数据上使用 Python 的 struct module。
如果这不是您的目标,这里有一个简单的示例代码来重新排列一个 8 个字符的字符串:
def wordpairswapper(s):
return s[6:8] + s[4:6] + s[2:4] + s[0:2]
【讨论】:
>>> import re
>>> re.sub("(..)(..)","\\2\\1","12345678")
'34127856'
>>> re.sub("(....)(....)","\\2\\1","34127856")
'78563412'
【讨论】:
import re
re.sub(r'(..)(..)', r'\2\1', '12345678')
re.sub(r'(....)(....)', r'\2\1', '34127856')
【讨论】: