有没有一种Pythonic的方式可以在字符串的每个第二个元素中插入一个元素?
我有一个字符串:'aabbccdd',我希望最终结果是'aa-bb-cc-dd'。
我不确定该如何实现这一点。
>>> s = 'aabbccdd'
>>> '-'.join(s[i:i+2] for i in range(0, len(s), 2))
'aa-bb-cc-dd'
>>> s = '12345678'
>>> t = iter(s)
>>> '-'.join(a+b for a,b in zip(t, t))
'12-34-56-78'
< p > 另外,t
也可以通过以下方式消除
>>> '-'.join(a+b for a,b in zip(s[::2], s[1::2]))
'12-34-56-78'
这个算法是将字符串分成一组一组的,然后用 -
字符将它们连接起来。
这段代码是这样写的。首先,它将字符串拆分为奇数位和偶数位。
>>> s[::2], s[1::2]
('1357', '2468')
然后使用zip
函数将它们合并为一个元组的可迭代对象。
>>> list( zip(s[::2], s[1::2]) )
[('1', '2'), ('3', '4'), ('5', '6'), ('7', '8')]
但是元组不是我们想要的。这应该是一个字符串列表。这就是列表推导的目的。
>>> [a+b for a,b in zip(s[::2], s[1::2])]
['12', '34', '56', '78']
str.join()
来组合列表。>>> '-'.join(a+b for a,b in zip(s[::2], s[1::2]))
'12-34-56-78'
第一段代码与原始想法相同,但在字符串较长时消耗更少的内存。
>>> s = "aabbccd"
>>> from itertools import izip_longest
>>> '-'.join(a+b for a,b in izip_longest(s[::2], s[1::2], fillvalue=""))
'aa-bb-cc-d'
或者
>>> t = iter(s)
>>> '-'.join(a+b for a,b in izip_longest(t, t, fillvalue=""))
'aa-bb-cc-d'
>>> s = 'aabbccdd'
>>> '-'.join(re.findall('..', s))
'aa-bb-cc-dd'
然而,这个版本对于实际的配对要求非常严格:
>>> t = s + 'e'
>>> '-'.join(re.findall('..', t))
'aa-bb-cc-dd'
...因此,通过微调,你可以容忍奇长度的字符串:
>>> '-'.join(re.findall('..?', t))
'aa-bb-cc-dd-e'
PAIRS = re.compile('..').findall
out = '-'.join(PAIRS(in))
或者在真实的代码中我会使用:
def rejoined(src, sep='-', _split=re.compile('..').findall):
return sep.join(_split(src))
>>> rejoined('aabbccdd', sep=':')
'aa:bb:cc:dd'
我不时使用这样的方法,从6字节的二进制输入中创建MAC地址表示:
>>> addr = b'\xdc\xf7\x09\x11\xa0\x49'
>>> rejoined(addr[::-1].hex(), sep=':')
'49:a0:11:09:f7:dc'
..?
版本开始分享正则表达式的最佳版本。在我看来,事实上它会对于奇数长度的字符串默默地丢弃最后一个字符,这使得..
版本成为一个较弱的解决方案。 - Josiah Yoder这里是一个列表推导式,根据枚举的模数有条件地返回值,奇数的最后一个字符将单独成组:
for s in ['aabbccdd','aabbccdde']:
print(''.join([ char if not ind or ind % 2 else '-' + char
for ind,char in enumerate(s)
]
)
)
""" Output:
aa-bb-cc-dd
aa-bb-cc-dd-e
"""
"-".join([''.join(item) for item in zip(mystring1[::2],mystring1[1::2])])
正如PEP8所述:
不要依赖于CPython对形如
a += b
或a = a + b
的语句进行原地字符串连接的高效实现。即使在CPython中,这种优化也很脆弱(它仅适用于某些类型),而且在其他实现中根本不存在。
一种Pythonic的方法是避免这种连接,并允许您连接除字符串以外的可迭代对象:
':'.join(f'{s[i:i+2]}' for i in range(0, len(s), 2))
另一种更加功能化的方式可能是:
':'.join(map('{}{}'.format, *(s[::2], s[1::2])))
这种第二种方法有一个特殊的特点(或者说是bug),只能连接成对的字母。所以:
>>> s = 'abcdefghij'
'ab:cd:ef:gh:ij'
并且:
>>> s = 'abcdefghi'
'ab:cd:ef:gh'