Python: 循环中的字符串切片

-1 投票
2 回答
20355 浏览
提问于 2025-04-17 16:51

我正在尝试对以下字符串进行切片,但我的代码在第二次循环后没有返回任何内容。

s = "93011NULL                5011005874          A0000000000010000000000001JKL00000000NULL                                              00000000A63"

d = [5,20,20,1,16,9,3,8,50,8,1,2]

start = 0
for x in d:
    print(s[start:x])
    start += x

当我运行这段代码时,我只得到:

43011
NULL

接下来的十次循环都打印了"",也就是空字符串。理想情况下,它应该循环并根据变量d中给定的字符串长度将这个字符串切成几块。

我可能哪里做错了呢?

谢谢。

2 个回答

4

更新 1

针对你具体的问题,解决方案看起来是这样的:

s = "93011NULL                5011005874          A0000000000010000000000001JKL00000000NULL                                              00000000A63"
d = [5,20,20,1,16,9,3,8,50,8,1,2]

# Convert sizes to indexes
d = [sum(d[:i+1]) for i in range(len(d))]

splits = [s[i:j] for i, j in zip([0]+d, d+[None])]

print splits

输出

>>> 
['93011', 'NULL                ', '5011005874          ', 'A', '0000000000010000', '000000001', 'JKL', '00000000', 'NULL                                              ', '00000000', 'A', '63', '']

如果你需要切片,为什么不试试这个呢……

>>> s = 'AA111-99XYZ '

>>> d = [2, 4, 5, 8, 11]

>>> [s[i:j] for i, j in zip([0]+d, d+[None])]

['AA', '11', '1', '-99', 'XYZ', ' ']

解释

zip这个函数可以接收多个列表作为参数,然后把每个列表中对应位置的元素组合成一个新的列表。

>>> zip(d, d)
[(2, 2), (4, 4), (5, 5), (8, 8), (11, 11)]

我们需要的是 [(0, 2), (2, 4), (4, 5), (5, 8), (8, 11), (11, None)]。所以,列表中的元素需要向后移动一个位置。

>>> [0] + d
[0, 2, 4, 5, 8, 11]

>>> d + [None]
[2, 4, 5, 8, 11, None]

现在我们调用 zip

>>> zip([0] + d, d + [None])
[(0, 2), (2, 4), (4, 5), (5, 8), (8, 11), (11, None)]

接下来,我们调用 s[i:j],这会从索引 ij-1 之间切片。

>>> s[0:2]
'AA'
>>> s[2:4]
'11'

因此,我们创建一个列表推导式,用来为 zip 输出的每个条目生成一个切片列表。

[ s[i:j] for i, j in zip([0] + d, d + [None]) ] 

这相当于

[ s[i:j] for i, j in [(0, 2), (2, 4), (4, 5), (5, 8), (8, 11), (11, None)] ]

最后一部分,s[i:None]s[i:] 是一样的。

3

你的问题在于,你在切片的时候,第二个索引比第一个索引还大。根据你给的 d 的值,你的切片是这样的:

第一次迭代:0,5

第二次迭代:5,20

第三次迭代:25,20 <-- 这里就是问题所在。

注意,这个问题是因为你一直在给 start 加值,所以它越来越大。

补充说明:我刚意识到你可能误解了 Python 的切片语法。第二个值并不是切片的长度,而是第一个包含在切片中的元素的索引。

如果你想把字符串分割成不重叠的片段,使得这些片段拼起来等于原始字符串,那么你应该用 = 而不是 +=,并设置 d 使得 d 中的每个值都是你希望切割的位置的索引。(注意这些索引必须是递增的。)

另外,如果你希望 d 中的每个值代表每个切片的大小,可以使用以下代码:

for x in d:
    print s[start:start+x]
    start += x

撰写回答