Pisahkan string setiap karakter ke-n?

382

Apakah mungkin untuk membagi string setiap karakter ke-n?

Misalnya, saya memiliki string yang berisi yang berikut ini:

'1234567890'

Bagaimana saya bisa membuatnya terlihat seperti ini:

['12','34','56','78','90']
Brandon L Burnett
sumber

Jawaban:

550
>>> line = '1234567890'
>>> n = 2
>>> [line[i:i+n] for i in range(0, len(line), n)]
['12', '34', '56', '78', '90']
satomacoto
sumber
35
Ini adalah jawaban yang sangat hebat karena tidak berbelit-belit dan fakta itu memungkinkan Anda untuk mengingat metode ini dengan mudah karena kesederhanaannya
Trevor Rudolph
1
@TrevorRudolph Hanya melakukan persis seperti yang Anda katakan. Jawaban di atas sebenarnya hanya untuk loop tetapi diekspresikan secara python. Juga, jika Anda perlu mengingat jawaban "sederhana", ada setidaknya ratusan ribu cara untuk mengingatnya: membintangi halaman di stackoverflow; menyalin dan menempelkan ke email; menyimpan file "membantu" dengan hal-hal yang ingin Anda ingat; cukup menggunakan mesin pencari modern kapan pun Anda membutuhkan sesuatu; menggunakan bookmark di (mungkin) setiap browser web; dll
dylnmc
1
Pada meskipun kedua, tampak seolah-olah Anda adalah serius. Saya benar-benar berharap Anda serius karena itu tidak berbelit - belit.
dylnmc
1
saya serius, saya menggunakan kode ini di konverter biner saya di emulator, saya suka itu adalah pythonic untuk loop haaha tetapi terima kasih untuk lebih lanjut memecah mengapa saya menikmati metode ini!
Trevor Rudolph
5
Ironisnya, mencoba menggunakan kata-kata dengan cara yang tidak memiliki makna tersembunyi, akan sering menghasilkan kalimat yang berbelit-belit.
deed02392
208

Agar lengkap, Anda bisa melakukan ini dengan regex:

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

Untuk jumlah karakter ganjil, Anda dapat melakukan ini:

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

Anda juga dapat melakukan hal berikut, untuk menyederhanakan regex untuk potongan yang lebih lama:

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

Dan Anda dapat menggunakan re.finditerjika string tersebut panjang untuk menghasilkan chunk by chunk.

serigala
sumber
3
Sejauh ini, inilah jawaban terbaik di sini dan layak berada di puncak. Seseorang bahkan dapat menulis '.'*nuntuk membuatnya lebih jelas. Tidak ada yang bergabung, tidak ada zip, tidak ada loop, tidak ada pemahaman daftar; temukan saja dua karakter berikutnya di sebelah satu sama lain, yang persis bagaimana otak manusia memikirkannya. Jika Monty Python masih hidup, dia akan menyukai metode ini!
jdk1.0
Ini adalah metode tercepat untuk string yang cukup panjang juga: gitlab.com/snippets/1908857
Ralph Bolton
Ini tidak akan berfungsi jika string berisi baris baru. Ini perlu flags=re.S.
Aran-Fey
ahhh .... regex .... kenapa aku tidak memikirkan XD itu
Tn. PizzaGuy
148

Sudah ada fungsi inbuilt di python untuk ini.

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

Ini adalah apa yang dikatakan docstring untuk 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.
'''
Diptangsu Goswami
sumber
2
print (wrap ('12345678', 3)) membagi string menjadi kelompok-kelompok 3 digit, tetapi dimulai di depan dan bukan di belakang. Hasil: ['123', '456', '78']
Atalanttore
2
Sangat menarik untuk belajar tentang 'membungkus' namun tidak melakukan persis apa yang diminta di atas. Ini lebih berorientasi pada menampilkan teks, daripada memisahkan string ke sejumlah karakter.
Oren
2
wrapmungkin tidak mengembalikan apa yang diminta jika string berisi ruang. misalnya wrap('0 1 2 3 4 5', 2)pengembalian ['0', '1', '2', '3', '4', '5'](elemen dilucuti)
satomacoto
3
Ini memang menjawab pertanyaan, tetapi apa yang terjadi jika ada spasi dan Anda ingin mereka dipertahankan dalam karakter yang terpisah? wrap () menghilangkan spasi jika jatuh tepat setelah sekelompok karakter yang terpisah
Iron Attorney
1
Ini berfungsi buruk jika Anda ingin membagi teks dengan tanda hubung (angka yang Anda berikan sebagai argumen sebenarnya adalah jumlah MAKSIMUM karakter, bukan yang tepat, dan rusak yaitu pada tanda hubung dan spasi putih).
MrVocabulary
81

Cara umum lainnya untuk mengelompokkan elemen ke dalam grup n-length:

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

Metode ini datang langsung dari dokumen untuk zip().

Andrew Clark
sumber
2
Dalam [19]: a = "hello world"; daftar (peta ("" .join, zip (* [iter (a)] * 4))) dapatkan hasilnya ['neraka', 'o wo'].
truease.com
16
Jika seseorang merasa zip(*[iter(s)]*2)sulit untuk dipahami, baca Bagaimana cara zip(*[iter(s)]*n)kerjanya di Python? .
Grijesh Chauhan
15
Ini tidak termasuk jumlah ganjil karakter, itu hanya akan menjatuhkan karakter tersebut: >>> map(''.join, zip(*[iter('01234567')]*5))->['01234']
Bjorn
3
Untuk juga menangani jumlah karakter ganjil, gantikan zip()dengan itertools.zip_longest():map(''.join, zip_longest(*[iter(s)]*2, fillvalue=''))
Paulo Freitas
Juga berguna: dokumen untukmaps()
winklerrr
58

Saya pikir ini lebih pendek dan lebih mudah dibaca daripada versi 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)))
Russell Borogove
sumber
7
tetapi tidak benar-benar efisien: bila diterapkan pada string: terlalu banyak salinan
Eric
1
Ini juga tidak bekerja jika seq adalah generator, yang adalah apa yang versi itertools adalah untuk . Bukan berarti OP meminta itu, tetapi tidak adil untuk mengkritik versi itertool tidak sesederhana itu.
CryingCyclops
25

Saya suka solusi ini:

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

Menggunakan more-itertools dari PyPI:

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

Anda bisa menggunakan grouper()resep dari 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)

Fungsi-fungsi ini hemat memori dan berfungsi dengan semua iterables.

Eugene Yarmash
sumber
6

Coba kode berikut:

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)))
enderskill
sumber
Jawaban Anda tidak memenuhi persyaratan OP, Anda harus menggunakannya yield ''.join(piece)untuk membuatnya berfungsi seperti yang diharapkan: 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']
ben w
sumber
4

Coba ini:

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

Keluaran:

['12', '34', '56', '78', '90']
U10-Maju
sumber
3

Seperti biasa, untuk mereka yang suka one 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])]
Sqripter
sumber
Ketika saya menjalankan ini di Python Fiddle dengan print(line)saya dapatkan this is a line split into n characterssebagai output. Mungkin Anda lebih baik menempatkan: line = [line[i * n:i * n+n] for i,blah in enumerate(line[::n])]? Perbaiki ini dan ini jawaban yang bagus :).
Apa yang ada di Google Search
Bisakah Anda menjelaskan ,blahdan mengapa itu perlu? Saya perhatikan saya dapat mengganti blahdengan karakter alfa apa pun, tetapi bukan angka, dan tidak dapat menghapus blahatau / dan koma. Editor saya menyarankan menambahkan spasi putih setelah ,: s
toonarmycaptain
enumeratemengembalikan dua iterables, jadi Anda perlu dua tempat untuk meletakkannya. Tetapi Anda sebenarnya tidak membutuhkan iterable kedua untuk apa pun dalam kasus ini.
Daniel F
1
Daripada blahsaya lebih suka menggunakan underscore atau double underscore, lihat: stackoverflow.com/questions/5893163/…
Andy Royal
2

Solusi rekursif sederhana untuk string pendek:

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

print(split('1234567890', 2))

Atau dalam bentuk seperti itu:

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)

, yang menggambarkan pola pembagian dan penaklukan yang khas dalam pendekatan rekursif secara lebih eksplisit (meskipun secara praktis tidak perlu dilakukan dengan cara ini)

englealuze
sumber
2

Saya terjebak dalam skenario yang sama.

Ini berhasil untuk saya

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

Keluaran

['12', '34', '56', '78', '90']
Strick
sumber
1

more_itertools.slicedtelah disebutkan sebelumnya. Berikut adalah empat opsi lagi dari more_itertoolsperpustakaan:

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

Masing-masing opsi terakhir menghasilkan output berikut:

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

Dokumentasi untuk opsi yang dibahas: grouper, chunked, windowed,split_after

pylang
sumber
0

Ini dapat dicapai dengan loop sederhana.

a = '1234567890a'
result = []

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

Outputnya terlihat seperti ['12', '34', '56', '78', '90', 'a']

Kasem007
sumber
2
Sementara kode ini dapat menjawab pertanyaan, memberikan konteks tambahan tentang mengapa dan / atau bagaimana kode ini menjawab pertanyaan meningkatkan nilai jangka panjangnya.
β.εηοιτ.βε
2
Ini adalah solusi yang sama seperti di sini: stackoverflow.com/a/59091507/7851470
Georgy