在Python中一次迭代字符串2(或n)个字符

时间:2009-07-22 01:24:54

标签: python iteration

今天早些时候,我需要一次迭代一个字符串2个字符来解析格式化为"+c-R+D-E"的字符串(还有一些额外的字母)。

我最终得到了这个,但它看起来很难看。我最后评论它正在做什么,因为它感觉不明显。它几乎似乎是pythonic,但并不完全。

# Might not be exact, but you get the idea, use the step
# parameter of range() and slicing to grab 2 chars at a time
s = "+c-R+D-e"
for op, code in (s[i:i+2] for i in range(0, len(s), 2)):
  print op, code

有更好/更清洁的方法吗?

11 个答案:

答案 0 :(得分:46)

Dunno关于清洁,但还有另一种选择:

for (op, code) in zip(s[0::2], s[1::2]):
    print op, code

无复制版本:

from itertools import izip, islice
for (op, code) in izip(islice(s, 0, None, 2), islice(s, 1, None, 2)):
    print op, code

答案 1 :(得分:13)

也许这会更干净?

s = "+c-R+D-e"
for i in xrange(0, len(s), 2):
    op, code = s[i:i+2]
    print op, code

你也许可以写一个发电机来做你想做的事情,也许这会更加pythonic:)

答案 2 :(得分:5)

Triptych启发了这个更通用的解决方案:

def slicen(s, n, truncate=False):
    assert n > 0
    while len(s) >= n:
        yield s[:n]
        s = s[n:]
    if len(s) and not truncate:
        yield s

for op, code in slicen("+c-R+D-e", 2):
    print op,code

答案 3 :(得分:4)

from itertools import izip_longest
def grouper(iterable, n, fillvalue=None):
    args = [iter(iterable)] * n
    return izip_longest(*args, fillvalue=fillvalue)
def main():
    s = "+c-R+D-e"
    for item in grouper(s, 2):
        print ' '.join(item)
if __name__ == "__main__":
    main()
##output
##+ c
##- R
##+ D
##- e

izip_longest需要Python 2.6(或更高版本)。如果在Python 2.4或2.5上,请使用documentizip_longest的定义或将grouper函数更改为:

from itertools import izip, chain, repeat
def grouper(iterable, n, padvalue=None):
    return izip(*[chain(iterable, repeat(padvalue, n-1))]*n)

答案 4 :(得分:3)

发电机的绝佳机会。对于较大的列表,这将比压缩每个其他元素更有效。请注意,此版本还处理悬挂op s

的字符串
def opcodes(s):
    while True:
        try:
            op   = s[0]
            code = s[1]
            s    = s[2:]
        except IndexError:
            return
        yield op,code        


for op,code in opcodes("+c-R+D-e"):
   print op,code

编辑:次要重写以避免ValueError异常。

答案 5 :(得分:2)

其他答案适用于n = 2,但对于一般情况,您可以尝试:

def slicen(s, n, truncate=False):
    nslices = len(s) / n
    if not truncate and (len(s) % n):
        nslices += 1
    return (s[i*n:n*(i+1)] for i in range(nslices))

>>> s = '+c-R+D-e'
>>> for op, code in slicen(s, 2):
...     print op, code
... 
+ c
- R
+ D
- e

>>> for a, b, c in slicen(s, 3):
...     print a, b, c
... 
+ c -
R + D
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ValueError: need more than 2 values to unpack

>>> for a, b, c in slicen(s,3,True):
...     print a, b, c
... 
+ c -
R + D

答案 6 :(得分:2)

这种方法支持每个结果的任意数量的元素,懒惰地评估,输入iterable可以是生成器(不尝试索引):

import itertools

def groups_of_n(n, iterable):
    c = itertools.count()
    for _, gen in itertools.groupby(iterable, lambda x: c.next() / n):
        yield gen

任何遗留元素都会在较短的列表中返回。

使用示例:

for g in groups_of_n(4, xrange(21)):
    print list(g)

[0, 1, 2, 3]
[4, 5, 6, 7]
[8, 9, 10, 11]
[12, 13, 14, 15]
[16, 17, 18, 19]
[20]

答案 7 :(得分:1)

>>> s = "+c-R+D-e"
>>> s
'+c-R+D-e'
>>> s[::2]
'+-+-'
>>>

答案 8 :(得分:1)

也许不是最有效的,但如果你喜欢正则表达式......

import re
s = "+c-R+D-e"
for op, code in re.findall('(.)(.)', s):
    print op, code

答案 9 :(得分:0)

我遇到了类似的问题。结束这样的事情:

ops = iter("+c-R+D-e")
for op in ops
    code = ops.next()

    print op, code

我觉得它最具可读性。

答案 10 :(得分:0)

这是我的答案,我的眼睛有点清洁:

for i in range(0, len(string) - 1):
    if i % 2 == 0:
        print string[i:i+2]