Dividir string a cada enésimo caractere?

382

É possível dividir uma string a cada enésimo caractere?

Por exemplo, suponha que eu tenha uma sequência que contenha o seguinte:

'1234567890'

Como faço para que fique assim:

['12','34','56','78','90']
Brandon L Burnett
fonte

Respostas:

550
>>> line = '1234567890'
>>> n = 2
>>> [line[i:i+n] for i in range(0, len(line), n)]
['12', '34', '56', '78', '90']
satomacoto
fonte
35
Este é realmente um grande resposta porque não é complicado de qualquer maneira e esse fato permite que você lembre-se o método facilmente devido à sua simplicidade
Trevor Rudolph
11
@TrevorRudolph Ele faz exatamente o que você diz. A resposta acima é realmente apenas um loop for, mas expressa pythonically. Além disso, se você precisar se lembrar de uma resposta "simplista", existem pelo menos centenas de milhares de maneiras de se lembrar delas: estrelando a página no stackoverflow; copiar e colar em um email; mantendo um arquivo "útil" com coisas que você deseja lembrar; simplesmente usando um mecanismo de busca moderno sempre que precisar de algo; usando favoritos em (provavelmente) todos os navegadores da web; etc.
dylnmc
11
No segundo, porém, parece que você está falando sério. Na verdade, espero que você esteja falando sério, já que não é realmente complicado.
Dllnmc
11
eu estava falando sério, usei esse código no meu conversor binário em um emulador, gostei que fosse um python para loop haaha, mas obrigado por saber mais sobre por que gosto do método!
Trevor Rudolph
5
Ironicamente, tentar usar palavras de uma maneira que não tenha significado oculto, geralmente resultará em sentenças complicadas.
precisa saber é o seguinte
208

Apenas para concluir, você pode fazer isso com uma regex:

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

Para um número ímpar de caracteres, você pode fazer isso:

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

Você também pode fazer o seguinte, para simplificar a regex para pedaços mais longos:

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

E você pode usar re.finditerse a sequência for longa para gerar pedaço por pedaço.

o lobo
fonte
3
Esta é de longe a melhor resposta aqui e merece estar no topo. Pode-se até escrever '.'*npara deixar mais claro. Sem junção, sem zíper, sem loops, sem compreensão de lista; basta encontrar os próximos dois caracteres um ao lado do outro, que é exatamente como o cérebro humano pensa sobre isso. Se Monty Python ainda estivesse vivo, ele adoraria esse método!
jdk1.0
Este é o método mais rápido para seqüências de caracteres razoavelmente longas: gitlab.com/snippets/1908857
Ralph Bolton
Isso não funcionará se a sequência contiver novas linhas. Isso precisa flags=re.S.
Aran-Fey
ahhh .... regex .... por que eu não pensei nisso XD
Mr PizzaGuy 29/04
148

Já existe uma função embutida em python para isso.

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

Isto é o que a documentação do wrap diz:

>>> 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.
'''
Diptangsu Goswami
fonte
2
print (quebra automática ('12345678', 3)) divide a sequência em grupos de 3 dígitos, mas começa na frente e não atrás. Resultado: ['123', '456', '78']
Atalanttore
2
É interessante aprender sobre o 'wrap', mas não está fazendo exatamente o que foi solicitado acima. É mais voltado para a exibição de texto, em vez de dividir uma sequência em um número fixo de caracteres.
Oren
2
wrappode não retornar o que é solicitado se a string contiver espaço. por exemplo, wrap('0 1 2 3 4 5', 2)os retornos ['0', '1', '2', '3', '4', '5'](os elementos são retirados)
satomacoto
3
Isso realmente responde à pergunta, mas o que acontece se houver espaços e você desejar que eles sejam mantidos nos caracteres divididos? wrap () remove os espaços se eles caírem logo após um grupo dividido de caracteres #
Iron Attorney
11
Isso funciona mal se você deseja dividir o texto com hífens (o número que você fornece como argumento é na verdade o número MÁXIMO de caracteres, não o exato, e ele quebra, por exemplo, em hífens e espaços em branco).
MrVocabulary 6/08/19
81

Outra maneira comum de agrupar elementos em grupos de comprimento n:

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

Este método vem diretamente dos documentos para zip().

Andrew Clark
fonte
2
Em [19]: a = "olá mundo"; list (map ("" .join, zip (* [iter (a)] * 4))) obtém o resultado ['inferno', 'o wo'].
truease.com
16
Se alguém achar zip(*[iter(s)]*2)difícil de entender, leia Como zip(*[iter(s)]*n)funciona no Python? .
Grijesh Chauhan
15
Isso não explica um número ímpar de caracteres, ele simplesmente os solta: >>> map(''.join, zip(*[iter('01234567')]*5))->['01234']
Bjorn
3
Para lidar também número ímpar de caracteres apenas substituir zip()com itertools.zip_longest():map(''.join, zip_longest(*[iter(s)]*2, fillvalue=''))
Paulo Freitas
Também é útil: docs formaps()
winklerrr 23/04/19
58

Eu acho que isso é mais curto e mais legível que a versão 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)))
Russell Borogove
fonte
7
mas não é realmente eficiente: quando aplicada às cordas: muitas cópias
Eric
11
Ele também não funciona se seq é um gerador, que é o que a versão itertools é para . Não que o OP pedisse isso, mas não é justo criticar a versão do itertool por não ser tão simples.
CryingCyclops
25

Eu gosto desta solução:

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

Usando more-itertools do PyPI:

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

Você pode usar a grouper()receita de itertools:

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)

Essas funções são eficientes na memória e funcionam com quaisquer iteráveis.

Eugene Yarmash
fonte
6

Tente o seguinte código:

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)))
enderskill
fonte
A sua resposta não cumprir a exigência do OP, você tem que usar yield ''.join(piece)para fazê-lo funcionar como esperado: eval.in/813878
Paulo Freitas
5
>>> 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']
ben w
fonte
4

Tente o seguinte:

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

Resultado:

['12', '34', '56', '78', '90']
Sub-10
fonte
3

Como sempre, para quem gosta de um forro

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])]
Sqripter
fonte
Quando eu executo isso no Python Fiddle com um print(line)eu recebo this is a line split into n characterscomo saída. Você poderia estar melhor colocando line = [line[i * n:i * n+n] for i,blah in enumerate(line[::n])]:? Corrija isso e é uma boa resposta :).
O que há em uma Pesquisa no Google
Você pode explicar ,blahe por que é necessário? Percebo que posso substituir blahpor qualquer caractere alfa, mas não números, e não consigo remover a blahou / e a vírgula. Meu editor sugere adicionar espaços em branco após ,: s
toonarmycaptain 17/17/17
enumerateretorna duas iteráveis, então você precisa de dois lugares para colocá-las. Mas você não precisa do segundo iterável para nada neste caso.
Daniel F
11
Ao invés de blaheu prefiro usar um sublinhado ou sublinhado duplo, consulte: stackoverflow.com/questions/5893163/...
Andy Real
2

Uma solução recursiva simples para string curta:

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

print(split('1234567890', 2))

Ou de tal forma:

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)

, que ilustra o padrão típico de divisão e conquista na abordagem recursiva de forma mais explícita (embora praticamente não seja necessário fazê-lo dessa maneira)

englealuze
fonte
2

Eu estava preso no mesmo cenário.

Isso funcionou para mim

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

Resultado

['12', '34', '56', '78', '90']
Strick
fonte
1

more_itertools.slicedjá foi mencionado antes. Aqui estão mais quatro opções da more_itertoolsbiblioteca:

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)]

Cada uma das últimas opções produz a seguinte saída:

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

Documentação para opções discutidas: grouper, chunked, windowed,split_after

pylang
fonte
0

Isso pode ser conseguido por um loop for simples.

a = '1234567890a'
result = []

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

A saída é semelhante a ['12', '34', '56', '78', '90', 'a']

Kasem007
fonte
2
Embora esse código possa responder à pergunta, fornecer um contexto adicional a respeito de por que e / ou como esse código responde à pergunta melhora seu valor a longo prazo.
β.εηοιτ.βε
2
Esta é a mesma solução que aqui: stackoverflow.com/a/59091507/7851470
Georgy