python remove - Dividir string a cada enésimo caractere?



html from (18)

>>> line = '1234567890'
>>> n = 2
>>> [line[i:i+n] for i in range(0, len(line), n)]
['12', '34', '56', '78', '90']

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

Por exemplo, suponha que eu tenha uma string contendo o seguinte:

'1234567890'

Como posso fazer com que seja assim:

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

Uma possibilidade é usar expressões regulares:

import re
re.findall("\w{3}", your_string)

Apenas para ser completo, você pode fazer isso com um regex:

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

Como apontado no comentário, você pode fazer isso:

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

Você também pode fazer o seguinte para simplificar o regex para partes mais longas:

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

E você pode usar re.finditer se a string for longa para gerar chunk por pedaço.


Você pode usar a receita de grouper() do 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 em termos de memória e funcionam com quaisquer iteráveis.


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

Eu sei que esta pergunta é antiga, mas este é o caminho mais curto para fazer isso eu estou ciente de:

def split_every_n(S, n):
  return [S[i*n:(i+1)*n] for i in range(len(S) / n)]

Isso, entretanto, pressupõe que o comprimento da sua string é um múltiplo de n. Caso contrário, você teria que preenchê-lo.


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 docstring para 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.
'''

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

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

Esse método vem direto dos documentos para zip() .


Tente isto:

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

Saída:

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

Eu estou usando isso:

list(''.join(s) for s in zip(my_str[::2], my_str[1::2]))

ou você pode usar qualquer outro número n vez de 2 .


more_itertools.sliced foi mentioned antes. Aqui estão mais quatro opções da biblioteca 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)]

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

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

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


Spooky one - tentou inventar mais uma resposta:

def split(s, chunk_size):
    a = zip(*[s[i::chunk_size] for i in range(chunk_size)])
    return [''.join(t) for t in a]

print(split('1234567890', 1))
print(split('1234567890', 2))
print(split('1234567890', 3))

Fora

['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']
['12', '34', '56', '78', '90']
['123', '456', '789']

def split(s, n):
  """
  Split string every nth character

  Parameters
  ----------
  s: string
  n: value of nth
  """
  new_list = []
  for i in range(0, len(s), n):
    new_list.append(s[i:i+n])
  return new_list

print(split('1234567890', 2))

Usando more-itertools do PyPI:

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

Eu acho que isso é mais curto e mais legível do que a versão do 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)))

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 dividir e conquistar na abordagem recursiva de forma mais explícita (embora praticamente não seja necessário fazê-lo dessa maneira)


Eu gosto desta solução:

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

Você precisa decodificar a string de bytes e transformá-la em uma string de caracteres (unicode).

b'hello'.decode(encoding)

ou

str(b'hello', encoding)




python