¿Dividir cadena cada enésimo carácter?


Respuestas:


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

35
Esta es una respuesta realmente excelente porque no es complicado de ninguna manera y ese hecho le permite recordar el método fácilmente debido a su simplicidad
Trevor Rudolph

1
@TrevorRudolph Solo hace exactamente lo que le dices. La respuesta anterior es realmente solo un bucle for, pero se expresa pitónicamente. Además, si necesita recordar una respuesta "simplista", hay al menos cientos de miles de formas de recordarlas: destacar la página en stackoverflow; copiar y luego pegar en un correo electrónico; mantener un archivo "útil" con cosas que desea recordar; simplemente usando un motor de búsqueda moderno siempre que necesite algo; usando marcadores en (probablemente) cada navegador web; etc.
dylnmc

1
En el segundo, sin embargo, parece como si usted es serio. De hecho, espero que hables en serio, ya que realmente no es complicado.
dylnmc

1
estaba hablando en serio, usé este código en mi convertidor binario en un emulador, me gustó que fuera un pitón para el bucle jajaja pero gracias por desglosar aún más por qué me gusta el método.
Trevor Rudolph el

55
Irónicamente, tratar de usar palabras de una manera que no tenga un significado oculto, a menudo resultará en oraciones complicadas.
deed02392

208

Solo para completar, puedes hacer esto con una expresión regular:

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

Para un número impar de caracteres, puede hacer esto:

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

También puede hacer lo siguiente para simplificar la expresión regular para fragmentos más largos:

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

Y puede usar re.finditersi la cadena es larga para generar fragmento por fragmento.


3
Esta es, con mucho, la mejor respuesta aquí y merece estar en la cima. Incluso se podría escribir '.'*npara dejarlo más claro. Sin unión, sin compresión, sin bucles, sin comprensión de la lista; solo encuentra los siguientes dos personajes uno al lado del otro, que es exactamente como un cerebro humano piensa al respecto. Si Monty Python todavía estuviera vivo, ¡le encantaría este método!
jdk1.0

Este es el método más rápido para cadenas razonablemente largas también: gitlab.com/snippets/1908857
Ralph Bolton el

Esto no funcionará si la cadena contiene nuevas líneas. Esto necesita flags=re.S.
Aran-Fey

ahhh .... regex .... por qué no pensé en eso XD
Mr PizzaGuy

148

Ya hay una función incorporada en Python para esto.

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

Esto es lo que dice la cadena de documentación para 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.
'''

2
print (wrap ('12345678', 3)) divide la cadena en grupos de 3 dígitos, pero comienza delante y no detrás. Resultado: ['123', '456', '78']
Atalanttore

2
Es interesante aprender sobre 'wrap', pero no está haciendo exactamente lo que se pidió anteriormente. Está más orientado a mostrar texto, en lugar de dividir una cadena en un número fijo de caracteres.
Oren

2
wrapEs posible que no devuelva lo que se solicita si la cadena contiene espacio. por ejemplo, wrap('0 1 2 3 4 5', 2)devoluciones ['0', '1', '2', '3', '4', '5'](los elementos se
eliminan

3
De hecho, esto responde a la pregunta, pero ¿qué sucede si hay espacios y desea que se mantengan en los caracteres divididos? wrap () elimina espacios si caen directamente después de un grupo dividido de personajes
Iron Attorney

1
Esto funciona mal si desea dividir el texto con guiones (el número que da como argumento es en realidad el número MÁXIMO de caracteres, no uno exacto, y se rompe, es decir, en guiones y espacios en blanco).
MrVocabulary

81

Otra forma común de agrupar elementos en grupos de longitud n:

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

Este método viene directamente de los documentos para zip().


2
En [19]: a = "hola mundo"; list (map ("" .join, zip (* [iter (a)] * 4))) obtiene el resultado ['hell', 'o wo'].
truease.com

16
Si a alguien le resulta zip(*[iter(s)]*2)difícil de entender, lea ¿Cómo zip(*[iter(s)]*n)funciona en Python? .
Grijesh Chauhan

15
Esto no tiene en cuenta un número impar de caracteres, simplemente los eliminará: >>> map(''.join, zip(*[iter('01234567')]*5))->['01234']
Bjorn

3
Para manejar también un número impar de caracteres simplemente reemplace zip()con itertools.zip_longest():map(''.join, zip_longest(*[iter(s)]*2, fillvalue=''))
Paulo Freitas

También útil: documentos paramaps()
winklerrr

58

Creo que esto es más corto y más legible que la versión de 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)))

77
pero no realmente eficiente: cuando se aplica a cadenas: demasiadas copias
Eric

1
También no funciona si la SEC es un generador, que es lo que la versión itertools es para . No es que OP haya pedido eso, pero no es justo criticar que la versión de itertool no sea tan simple.
CryingCyclops

25

Me gusta esta solución:

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

25

Usando más itertools de PyPI:

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

12

Puedes usar la grouper()receta 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)

Estas funciones son eficientes en memoria y funcionan con cualquier iterable.


6

Prueba el siguiente 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)))

Su respuesta no cumple con el requisito de OP, debe usarla yield ''.join(piece)para que funcione como se esperaba: 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']

4

Prueba esto:

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

Salida:

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

3

Como siempre, para aquellos que aman uno

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

Cuando ejecuto esto en Python violín con un print(line)recibo this is a line split into n characterscomo la salida. ¿Podría ser mejor poner line = [line[i * n:i * n+n] for i,blah in enumerate(line[::n])]:? Arregla esto y es una buena respuesta :).
Qué hay en una búsqueda de Google

¿Puedes explicar el ,blahy por qué es necesario? Noto que puedo reemplazar blahcon cualquier carácter alfabético / s, pero no números, y no puedo eliminar la blah/ o la coma. Mi editor sugiere agregar espacios en blanco después de ,: s
toonarmycaptain

enumeratedevuelve dos iterables, por lo que necesita dos lugares para colocarlos. Pero en realidad no necesita el segundo iterable para nada en este caso.
Daniel F

1
En lugar de blahpreferir usar un guión bajo o doble, ver: stackoverflow.com/questions/5893163/…
Andy Royal

2

Una solución recursiva simple para cadena corta:

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

print(split('1234567890', 2))

O en 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 el patrón típico de divide y vencerás en el enfoque recursivo de manera más explícita (aunque prácticamente no es necesario hacerlo de esta manera)


2

Estaba atrapado en el mismo escenario.

Esto funciono para mi

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

Salida

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

1

more_itertools.slicedha sido mencionado antes. Aquí hay cuatro opciones más de la 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 una de las últimas opciones produce el siguiente resultado:

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

La documentación de opciones discutidas: grouper, chunked, windowed,split_after


0

Esto se puede lograr mediante un bucle simple.

a = '1234567890a'
result = []

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

La salida se ve como ['12', '34', '56', '78', '90', 'a']


2
Si bien este código puede responder la pregunta, proporcionar un contexto adicional con respecto a por qué y / o cómo responde la pregunta mejora su valor a largo plazo.
β.εηοιτ.βε

2
Esta es la misma solución que aquí: stackoverflow.com/a/59091507/7851470
Georgy
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.