¿Es posible dividir una cadena cada enésimo carácter?
Por ejemplo, supongamos que tengo una cadena que contiene lo siguiente:
'1234567890'
¿Cómo puedo hacer que se vea así?
['12','34','56','78','90']
¿Es posible dividir una cadena cada enésimo carácter?
Por ejemplo, supongamos que tengo una cadena que contiene lo siguiente:
'1234567890'
¿Cómo puedo hacer que se vea así?
['12','34','56','78','90']
Respuestas:
>>> line = '1234567890'
>>> n = 2
>>> [line[i:i+n] for i in range(0, len(line), n)]
['12', '34', '56', '78', '90']
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.finditer
si la cadena es larga para generar fragmento por fragmento.
'.'*n
para 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!
flags=re.S
.
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.
'''
wrap
Es 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
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()
.
zip(*[iter(s)]*2)
difícil de entender, lea ¿Cómo zip(*[iter(s)]*n)
funciona en Python? .
>>> map(''.join, zip(*[iter('01234567')]*5))
->['01234']
zip()
con itertools.zip_longest()
:map(''.join, zip_longest(*[iter(s)]*2, fillvalue=''))
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)))
Usando más itertools de PyPI:
>>> from more_itertools import sliced
>>> list(sliced('1234567890', 2))
['12', '34', '56', '78', '90']
Puedes usar la grouper()
receta 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)
Estas funciones son eficientes en memoria y funcionan con cualquier iterable.
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)))
yield ''.join(piece)
para que funcione como se esperaba: 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']
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']
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])]
print(line)
recibo this is a line split into n characters
como 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 :).
,blah
y por qué es necesario? Noto que puedo reemplazar blah
con 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
enumerate
devuelve dos iterables, por lo que necesita dos lugares para colocarlos. Pero en realidad no necesita el segundo iterable para nada en este caso.
blah
preferir usar un guión bajo o doble, ver: stackoverflow.com/questions/5893163/…
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)
more_itertools.sliced
ha sido mencionado antes. Aquí hay cuatro opciones más de la 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 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
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']