Est-il possible de diviser une chaîne tous les n caractères?
Par exemple, supposons que j'ai une chaîne contenant les éléments suivants:
'1234567890'
Comment puis-je le faire ressembler à ceci:
['12','34','56','78','90']
Est-il possible de diviser une chaîne tous les n caractères?
Par exemple, supposons que j'ai une chaîne contenant les éléments suivants:
'1234567890'
Comment puis-je le faire ressembler à ceci:
['12','34','56','78','90']
Réponses:
>>> line = '1234567890'
>>> n = 2
>>> [line[i:i+n] for i in range(0, len(line), n)]
['12', '34', '56', '78', '90']
Juste pour être complet, vous pouvez le faire avec une expression régulière:
>>> import re
>>> re.findall('..','1234567890')
['12', '34', '56', '78', '90']
Pour un nombre impair de caractères, vous pouvez le faire:
>>> import re
>>> re.findall('..?', '123456789')
['12', '34', '56', '78', '9']
Vous pouvez également effectuer les opérations suivantes, pour simplifier l'expression régulière pour des segments plus longs:
>>> import re
>>> re.findall('.{1,2}', '123456789')
['12', '34', '56', '78', '9']
Et vous pouvez utiliser re.finditer
si la chaîne est longue pour générer morceau par morceau.
'.'*n
pour le rendre plus clair. Pas de jointure, pas de fermeture éclair, pas de boucles, pas de compréhension de liste; il suffit de trouver les deux personnages suivants l'un à côté de l'autre, ce qui est exactement la façon dont le cerveau humain y pense. Si Monty Python était encore en vie, il adorerait cette méthode!
flags=re.S
.
Il existe déjà une fonction intégrée en python pour cela.
>>> from textwrap import wrap
>>> s = '1234567890'
>>> wrap(s, 2)
['12', '34', '56', '78', '90']
Voici ce que dit la docstring pour 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
peut ne pas retourner ce qui est demandé si la chaîne contient de l'espace. par exemple wrap('0 1 2 3 4 5', 2)
retours ['0', '1', '2', '3', '4', '5']
(les éléments sont dépouillés)
Une autre façon courante de regrouper des éléments en groupes de n longueurs:
>>> s = '1234567890'
>>> map(''.join, zip(*[iter(s)]*2))
['12', '34', '56', '78', '90']
Cette méthode provient directement de la documentation de zip()
.
zip(*[iter(s)]*2)
difficile à comprendre, lisez Comment zip(*[iter(s)]*n)
fonctionne en Python? .
>>> map(''.join, zip(*[iter('01234567')]*5))
->['01234']
zip()
par itertools.zip_longest()
:map(''.join, zip_longest(*[iter(s)]*2, fillvalue=''))
Je pense que c'est plus court et plus lisible que la version 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)))
Utilisation d' outils plus itératifs de PyPI:
>>> from more_itertools import sliced
>>> list(sliced('1234567890', 2))
['12', '34', '56', '78', '90']
Vous pouvez utiliser la grouper()
recette 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)
Ces fonctions sont efficaces en mémoire et fonctionnent avec tous les itérables.
Essayez le code suivant:
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)
pour le faire fonctionner comme prévu: 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']
Essaye ça:
s='1234567890'
print([s[idx:idx+2] for idx,val in enumerate(s) if idx%2 == 0])
Production:
['12', '34', '56', '78', '90']
Comme toujours, pour ceux qui aiment un liners
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)
je reçois this is a line split into n characters
comme sortie. Pourriez-vous mieux mettre line = [line[i * n:i * n+n] for i,blah in enumerate(line[::n])]
:? Corrigez cela et c'est une bonne réponse :).
,blah
et pourquoi c'est nécessaire? Je remarque que je peux remplacer blah
par n'importe quel caractère alpha, mais pas de chiffres, et je ne peux pas supprimer le blah
/ ou la virgule. Mon éditeur suggère d'ajouter un espace après ,
: s
enumerate
renvoie deux itérables, vous avez donc besoin de deux emplacements pour les mettre. Mais vous n'avez en fait pas besoin du deuxième itérable pour quoi que ce soit dans ce cas.
blah
je préfère utiliser un trait de soulignement ou un double trait de soulignement, voir: stackoverflow.com/questions/5893163/…
Une solution récursive simple pour chaîne courte:
def split(s, n):
if len(s) < n:
return []
else:
return [s[:n]] + split(s[n:], n)
print(split('1234567890', 2))
Ou sous une telle forme:
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)
, qui illustre le modèle typique de division et de conquête dans une approche récursive de manière plus explicite (bien qu'il ne soit pas nécessaire de le faire de cette façon)
more_itertools.sliced
a déjà été mentionné . Voici quatre autres options de la more_itertools
bibliothèque:
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)]
Chacune de ces dernières options produit la sortie suivante:
['12', '34', '56', '78', '90']
Documentation pour les options discutées: grouper
, chunked
, windowed
,split_after
Ceci peut être réalisé par une simple boucle for.
a = '1234567890a'
result = []
for i in range(0, len(a), 2):
result.append(a[i : i + 2])
print(result)
La sortie ressemble à ['12', '34', '56', '78', '90', 'a']