È possibile dividere una stringa ogni ennesimo carattere?
Ad esempio, supponiamo che io abbia una stringa contenente quanto segue:
'1234567890'
Come posso farlo apparire così:
['12','34','56','78','90']
È possibile dividere una stringa ogni ennesimo carattere?
Ad esempio, supponiamo che io abbia una stringa contenente quanto segue:
'1234567890'
Come posso farlo apparire così:
['12','34','56','78','90']
Risposte:
>>> line = '1234567890'
>>> n = 2
>>> [line[i:i+n] for i in range(0, len(line), n)]
['12', '34', '56', '78', '90']
Solo per essere completo, puoi farlo con una regex:
>>> import re
>>> re.findall('..','1234567890')
['12', '34', '56', '78', '90']
Per un numero dispari di caratteri puoi farlo:
>>> import re
>>> re.findall('..?', '123456789')
['12', '34', '56', '78', '9']
Puoi anche fare quanto segue, per semplificare la regex per blocchi più lunghi:
>>> import re
>>> re.findall('.{1,2}', '123456789')
['12', '34', '56', '78', '9']
E puoi usare re.finditer
se la stringa è lunga per generare un blocco per blocco.
'.'*n
per renderlo più chiaro. Nessun join, nessun zipping, nessun loop, nessuna comprensione dell'elenco; trova i due personaggi seguenti uno accanto all'altro, ed è esattamente come un cervello umano ci pensa. Se Monty Python fosse ancora vivo, adorerebbe questo metodo!
flags=re.S
.
Per questo c'è già una funzione integrata in Python.
>>> from textwrap import wrap
>>> s = '1234567890'
>>> wrap(s, 2)
['12', '34', '56', '78', '90']
Questo è ciò che dice la documentazione per avvolgere:
>>> 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
potrebbe non restituire ciò che viene richiesto se la stringa contiene spazio. es. wrap('0 1 2 3 4 5', 2)
ritorni ['0', '1', '2', '3', '4', '5']
(gli elementi sono spogliati)
Un altro modo comune di raggruppare gli elementi in gruppi di lunghezza n:
>>> s = '1234567890'
>>> map(''.join, zip(*[iter(s)]*2))
['12', '34', '56', '78', '90']
Questo metodo deriva direttamente dalla documentazione di zip()
.
zip(*[iter(s)]*2)
difficile da capire, leggi Come zip(*[iter(s)]*n)
funziona in Python? .
>>> map(''.join, zip(*[iter('01234567')]*5))
->['01234']
zip()
con itertools.zip_longest()
:map(''.join, zip_longest(*[iter(s)]*2, fillvalue=''))
Penso che questo sia più breve e più leggibile rispetto alla versione 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)))
Utilizzando more-itertools da PyPI:
>>> from more_itertools import sliced
>>> list(sliced('1234567890', 2))
['12', '34', '56', '78', '90']
Puoi usare la grouper()
ricetta da 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)
Queste funzioni sono efficienti in termini di memoria e funzionano con tutti gli iterabili.
Prova il seguente codice:
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)
per farlo funzionare come previsto: 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']
Prova questo:
s='1234567890'
print([s[idx:idx+2] for idx,val in enumerate(s) if idx%2 == 0])
Produzione:
['12', '34', '56', '78', '90']
Come sempre, per chi ama una fodera
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)
ottengo this is a line split into n characters
come output. Potresti stare meglio mettendo line = [line[i * n:i * n+n] for i,blah in enumerate(line[::n])]
:? Risolvi questo problema ed è una buona risposta :).
,blah
e perché è necessario? Ho notato che posso sostituire blah
con qualsiasi carattere / i alfa, ma non numeri, e non posso rimuovere blah
o / e la virgola. Il mio editore suggerisce di aggiungere spazi bianchi dopo ,
: s
enumerate
restituisce due iterabili, quindi hai bisogno di due posti per metterli. Ma in questo caso non è necessario il secondo iterabile per nulla.
blah
preferisco usare un trattino basso o doppio, vedi: stackoverflow.com/questions/5893163/…
Una semplice soluzione ricorsiva per la stringa corta:
def split(s, n):
if len(s) < n:
return []
else:
return [s[:n]] + split(s[n:], n)
print(split('1234567890', 2))
O in tale 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)
, che illustra in modo più esplicito il tipico modello di divisione e conquista nell'approccio ricorsivo (anche se praticamente non è necessario farlo in questo modo)
more_itertools.sliced
è stato menzionato prima. Ecco altre quattro opzioni dalla more_itertools
libreria:
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)]
Ciascuna di queste ultime opzioni produce il seguente output:
['12', '34', '56', '78', '90']
La documentazione per le opzioni discusse: grouper
, chunked
, windowed
,split_after
Ciò può essere ottenuto con un semplice ciclo.
a = '1234567890a'
result = []
for i in range(0, len(a), 2):
result.append(a[i : i + 2])
print(result)
L'output è simile a ['12', '34', '56', '78', '90', 'a']