É 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']
É 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']
Respostas:
>>> line = '1234567890'
>>> n = 2
>>> [line[i:i+n] for i in range(0, len(line), n)]
['12', '34', '56', '78', '90']
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.finditer
se a sequência for longa para gerar pedaço por pedaço.
'.'*n
para 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!
flags=re.S
.
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.
'''
wrap
pode 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)
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()
.
zip(*[iter(s)]*2)
difícil de entender, leia Como zip(*[iter(s)]*n)
funciona no Python? .
>>> map(''.join, zip(*[iter('01234567')]*5))
->['01234']
zip()
com itertools.zip_longest()
:map(''.join, zip_longest(*[iter(s)]*2, fillvalue=''))
maps()
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)))
Usando more-itertools do PyPI:
>>> from more_itertools import sliced
>>> list(sliced('1234567890', 2))
['12', '34', '56', '78', '90']
Você pode usar a grouper()
receita de itertools
:
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)
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.
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)))
yield ''.join(piece)
para fazê-lo funcionar como esperado: eval.in/813878
>>> 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']
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])]
print(line)
eu recebo this is a line split into n characters
como 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 :).
,blah
e por que é necessário? Percebo que posso substituir blah
por qualquer caractere alfa, mas não números, e não consigo remover a blah
ou / e a vírgula. Meu editor sugere adicionar espaços em branco após ,
: s
enumerate
retorna 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.
blah
eu prefiro usar um sublinhado ou sublinhado duplo, consulte: stackoverflow.com/questions/5893163/...
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)
more_itertools.sliced
já foi mencionado antes. Aqui estão mais quatro opções da more_itertools
biblioteca:
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
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']