每第n个字符拆分字符串?

Posted

技术标签:

【中文标题】每第n个字符拆分字符串?【英文标题】:Split string every nth character? 【发布时间】:2012-03-17 12:42:17 【问题描述】:

是否可以每隔 n 个字符拆分一个字符串?

例如,假设我有一个包含以下内容的字符串:

'1234567890'

我怎样才能让它看起来像这样:

['12','34','56','78','90']

【问题讨论】:

这个问题的列表等价物:How do you split a list into evenly sized chunks?(虽然有些答案重叠并适用于两者,但每个答案都有一些独特之处) 【参考方案1】:

试试下面的代码:

from itertools import islice

def split_every(n, iterable):
    i = iter(iterable)
    piece = list(islice(i, n))
    while piece:
        yield piece
        piece = list(islice(i, n))

s = '1234567890'
print list(split_every(2, list(s)))

【讨论】:

您的答案不符合 OP 的要求,您必须使用 yield ''.join(piece) 使其按预期工作:eval.in/813878【参考方案2】:

我认为这比 itertools 版本更短更易读:

def split_by_n(seq, n):
    '''A generator to divide a sequence into chunks of n units.'''
    while seq:
        yield seq[:n]
        seq = seq[n:]

print(list(split_by_n('1234567890', 2)))

【讨论】:

但效率不高:应用于字符串时:副本太多 如果 seq 是一个生成器,它也不起作用,这是 itertools 版本 for 的。不是 OP 要求这样做,但批评 itertool 的版本不那么简单是不公平的。【参考方案3】:
>>> from functools import reduce
>>> from operator import add
>>> from itertools import izip
>>> x = iter('1234567890')
>>> [reduce(add, tup) for tup in izip(x, x)]
['12', '34', '56', '78', '90']
>>> x = iter('1234567890')
>>> [reduce(add, tup) for tup in izip(x, x, x)]
['123', '456', '789']

【讨论】:

【参考方案4】:
>>> line = '1234567890'
>>> n = 2
>>> [line[i:i+n] for i in range(0, len(line), n)]
['12', '34', '56', '78', '90']

【讨论】:

@TrevorRudolph 它只会按照您所说的去做。上面的答案实际上只是一个 for 循环,但用 python 表示。另外,如果你需要记住一个“简单”的答案,至少有几十万种方法可以记住它们:在 *** 上给页面加星标;复制然后粘贴到电子邮件中;将您想要记住的内容保存在“有用”的文件中;只需在需要时使用现代搜索引擎;在(可能)每个网络浏览器中使用书签;等 它更容易理解,但它的缺点是你必须引用'line'两次。 非常适合打印长行,例如for i in range(0, len(string), n): print(string[i:i+n]) 遵循哲学,保持简单;这就是蟒蛇般的优雅!【参考方案5】:

另一种将元素分组为 n 长度组的常用方法:

>>> s = '1234567890'
>>> map(''.join, zip(*[iter(s)]*2))
['12', '34', '56', '78', '90']

此方法直接来自zip() 的文档。

【讨论】:

在 [19]: a = "hello world"; list( map( "".join, zip(*[iter(a)]*4) ) ) 得到结果 ['hell', 'o wo']. 如果有人觉得zip(*[iter(s)]*2) 难以理解,请阅读How does zip(*[iter(s)]*n) work in Python?。 这不考虑奇数个字符,它只会删除这些字符:>>> map(''.join, zip(*[iter('01234567')]*5)) -> ['01234'] 要处理奇数个字符,只需将 zip() 替换为 itertools.zip_longest(): map(''.join, zip_longest(*[iter(s)]*2, fillvalue='')) 也很有用:maps()的文档【参考方案6】:

为了完整起见,您可以使用正则表达式来做到这一点:

>>> import re
>>> re.findall('..','1234567890')
['12', '34', '56', '78', '90']

对于奇数个字符,您可以这样做:

>>> import re
>>> re.findall('..?', '123456789')
['12', '34', '56', '78', '9']

您还可以执行以下操作,以简化较长块的正则表达式:

>>> import re
>>> re.findall('.1,2', '123456789')
['12', '34', '56', '78', '9']

如果字符串很长,您可以使用re.finditer 逐块生成。

【讨论】:

这是迄今为止最好的答案,值得放在首位。甚至可以写'.'*n 以使其更清楚。没有加入,没有压缩,没有循环,没有列表理解;只需找到彼此相邻的接下来的两个字符,这正是人脑的想法。如果 Monty Python 还活着,他会喜欢这种方法的! 这对于相当长的字符串也是最快的方法:gitlab.com/snippets/1908857 如果字符串包含换行符,这将不起作用。这需要flags=re.S【参考方案7】:

我喜欢这个解决方案:

s = '1234567890'
o = []
while s:
    o.append(s[:2])
    s = s[2:]

【讨论】:

【参考方案8】:

您可以使用来自itertoolsgrouper() 配方:

Python 2.x:

from itertools import izip_longest    

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

Python 3.x:

from itertools import zip_longest

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)

这些函数可节省内存并适用于任何可迭代对象。

【讨论】:

【参考方案9】:

一如既往,对于那些喜欢一个班轮的人

n = 2  
line = "this is a line split into n characters"  
line = [line[i * n:i * n+n] for i,blah in enumerate(line[::n])]

【讨论】:

当我在 Python Fiddle 中使用print(line) 运行它时,我得到this is a line split into n characters 作为输出。你可能会更好:line = [line[i * n:i * n+n] for i,blah in enumerate(line[::n])]?解决这个问题,这是一个很好的答案:)。 您能解释一下,blah 以及为什么它是必要的吗?我注意到我可以用任何字母字符替换blah,但不能用数字替换,并且不能删除blah 或/和逗号。我的编辑建议在, 之后添加空格:s enumerate 返回两个可迭代对象,因此您需要两个位置来放置它们。但在这种情况下,您实际上不需要第二个可迭代对象。 比起blah,我更喜欢使用下划线或双下划线,参见:***.com/questions/5893163/…【参考方案10】:

使用 PyPI 中的more-itertools:

>>> from more_itertools import sliced
>>> list(sliced('1234567890', 2))
['12', '34', '56', '78', '90']

【讨论】:

【参考方案11】:

more_itertools.sliced 以前是mentioned。以下是来自more_itertools 库的另外四个选项:

s = "1234567890"

["".join(c) for c in mit.grouper(2, s)]

["".join(c) for c in mit.chunked(s, 2)]

["".join(c) for c in mit.windowed(s, 2, step=2)]

["".join(c) for c in  mit.split_after(s, lambda x: int(x) % 2 == 0)]

后面的每个选项都会产生以下输出:

['12', '34', '56', '78', '90']

讨论选项的文档:grouperchunkedwindowedsplit_after

【讨论】:

【参考方案12】:

python 中已经为此提供了一个内置函数。

>>> from textwrap import wrap
>>> s = '1234567890'
>>> wrap(s, 2)
['12', '34', '56', '78', '90']

这是 wrap 的文档字符串所说的:

>>> help(wrap)
'''
Help on function wrap in module textwrap:

wrap(text, width=70, **kwargs)
    Wrap a single paragraph of text, returning a list of wrapped lines.

    Reformat the single paragraph in 'text' so it fits in lines of no
    more than 'width' columns, and return a list of wrapped lines.  By
    default, tabs in 'text' are expanded with string.expandtabs(), and
    all other whitespace characters (including newline) are converted to
    space.  See TextWrapper class for available keyword args to customize
    wrapping behaviour.
'''

【讨论】:

print(wrap('12345678', 3)) 将字符串分成 3 位数字组,但从前面而不是后面开始。结果:['123', '456', '78'] 了解 'wrap' 很有趣,但它并没有完全按照上面的要求进行。它更倾向于显示文本,而不是将字符串拆分为固定数量的字符。 如果字符串包含空格,wrap 可能不会返回所要求的内容。例如wrap('0 1 2 3 4 5', 2) 返回['0', '1', '2', '3', '4', '5'](元素被剥离) 这确实回答了这个问题,但是如果有空格并且您希望它们保留在拆分字符中会发生什么?如果空格直接落在一组字符之后,wrap() 会删除空格 如果你想用连字符分割文本,这效果很差(你作为参数给出的数字实际上是最大字符数,而不是确切的一个,它打破了连字符和空格)。 【参考方案13】:

试试这个:

s='1234567890'
print([s[idx:idx+2] for idx,val in enumerate(s) if idx%2 == 0])

输出:

['12', '34', '56', '78', '90']

【讨论】:

【参考方案14】:

一个简单的短字符串递归解决方案:

def split(s, n):
    if len(s) < n:
        return []
    else:
        return [s[:n]] + split(s[n:], n)

print(split('1234567890', 2))

或者是这样的形式:

def split(s, n):
    if len(s) < n:
        return []
    elif len(s) == n:
        return [s]
    else:
        return split(s[:n], n) + split(s[n:], n)

,它更明确地说明了递归方法中典型的分而治之模式(尽管实际上没有必要这样做)

【讨论】:

【参考方案15】:

我被困在同样的场景中。

这对我有用

x="1234567890"
n=2
list=[]
for i in range(0,len(x),n):
    list.append(x[i:i+n])
print(list)

输出

['12', '34', '56', '78', '90']

【讨论】:

list 是 Python 中的保留关键字,您应该将变量名称更改为其他名称,例如 my_list【参考方案16】:

这可以通过一个简单的 for 循环来实现。

a = '1234567890a'
result = []

for i in range(0, len(a), 2):
    result.append(a[i : i + 2])
print(result)

输出看起来像 ['12', '34', '56', '78', '90', 'a']

【讨论】:

虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。 这与这里的解决方案相同:***.com/a/59091507/7851470 这与投票最多的答案相同 - 除了最高答案使用列表理解这一事实。【参考方案17】:

groupby的解决方案:

from itertools import groupby, chain, repeat, cycle

text = "wwworldggggreattecchemggpwwwzaz"
n = 3
c = cycle(chain(repeat(0, n), repeat(1, n)))
res = ["".join(g) for _, g in groupby(text, lambda x: next(c))]
print(res)

输出:

['www', 'orl', 'dgg', 'ggr', 'eat', 'tec', 'che', 'mgg', 'pww', 'wza', 'z']

【讨论】:

以上是关于每第n个字符拆分字符串?的主要内容,如果未能解决你的问题,请参考以下文章

从字符串中选择每第 n 个字符

如何拆分Python列表每第N个元素

在其中每第 n 次出现时反转一个字符串[关闭]

如果字符串包含多个 \n,如何在每 25 个换行符(\n)上拆分一个字符串

如何将字符串拆分为 n 个字符的段?

javascript 拆分字符串N个字符长