Her nth karakterde bölünmüş dize?


Yanıtlar:


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

35
Bu gerçekten harika bir cevap çünkü herhangi bir şekilde kıvrılmadı ve bu gerçek, basitliği nedeniyle yöntemi kolayca hatırlamanızı sağlar
Trevor Rudolph

1
@TrevorRudolph Sadece tam olarak söylediklerini yapar. Yukarıdaki cevap gerçekten sadece bir for döngüsü, ancak pitonik olarak ifade edilir. Ayrıca, "basit" bir cevabı hatırlamanız gerekiyorsa, bunları hatırlamanın en az yüz binlerce yolu vardır: sayfayı stackoverflow'da oynatmak; bir e-postaya kopyalama ve yapıştırma; hatırlamak istediğiniz şeyler içeren bir "yararlı" dosya tutulması; bir şeye ihtiyacınız olduğunda sadece modern bir arama motoru kullanmak; (muhtemelen) her web tarayıcısında yer imleri kullanma; vb.
dylnmc

1
İkinci olarak , ciddi gibi görünüyorsunuz . Umarım ciddisinizdir çünkü gerçekten kıvrımlı değildir .
dylnmc

1
Ciddi oldu, ben bir emülatör benim ikili dönüştürücü bu kodu kullanılır, ben döngü haaha için bir pythonic sevdim ama neden yöntemi zevk daha da yıkmak için teşekkürler!
Trevor Rudolph

5
İronik olarak, kelimeleri gizli bir anlamı olmayacak şekilde kullanmaya çalışmak çoğu zaman kıvrımlı cümlelere yol açacaktır.
deed02392

208

Tam olarak söylemek gerekirse, bunu normal ifadeyle yapabilirsiniz:

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

Tek sayıda karakter için bunu yapabilirsiniz:

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

Daha uzun parçalar için normal ifadeyi basitleştirmek için aşağıdakileri de yapabilirsiniz:

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

Ve re.finditerdizge yığın tarafından yığın oluşturmak için uzunsa kullanabilirsiniz.


3
Bu, buradaki en iyi cevaptır ve zirvede olmayı hak ediyor. '.'*nDaha açık hale getirmek için bile yazı yazılabilir . Birleştirme yok, sıkıştırma yok, döngü yok, liste kavraması yok; sadece sonraki iki karakteri yan yana bul, tam olarak bir insan beyni onun hakkında böyle düşünüyor. Monty Python hala hayatta olsaydı, bu yöntemi çok isterdi!
jdk1.0

Bu, oldukça uzun dizeler için de en hızlı yöntemdir: gitlab.com/snippets/1908857
Ralph Bolton

Dize yeni satır içeriyorsa bu çalışmaz. Buna ihtiyaç var flags=re.S.
Aran-Fey

ahhh .... regex .... neden bu XD hakkında düşünmedim
Mr PizzaGuy

148

Bunun için zaten python'da dahili bir fonksiyon var.

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

Wrap için doktora şöyle diyor:

>>> 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)) dizeyi 3 basamaklı gruplara ayırır, ancak önden başlar ve arkasından başlamaz. Sonuç: ['123', '456', '78']
Atalanttore

2
'Sarma' hakkında bilgi edinmek ilginçtir, ancak yukarıda sorulanları tam olarak yapmamaktadır. Bir dizeyi sabit sayıda karaktere bölmektense, metni göstermeye yöneliktir.
Ören

2
wrapdize boşluk içeriyorsa sorulmayabilir. örneğin, wrap('0 1 2 3 4 5', 2)döndürür ['0', '1', '2', '3', '4', '5'](elemanlar çıkarılır)
satomacoto

3
Bu gerçekten soruyu cevaplıyor, ancak boşluklar varsa ve bölünmüş karakterlerde korunmasını istiyorsanız ne olur? wrap (), bölünmüş bir karakter grubundan hemen sonra düşerse boşlukları kaldırır
Iron Attorney

1
Metni tirelerle bölmek istiyorsanız bu işe yaramaz.
MrVocabulary

81

Öğeleri n-uzunluk gruplarına gruplamanın bir başka yaygın yolu:

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

Bu yöntem doğrudan için dokümanlardan gelir zip().


2
[19] 'da: a = "merhaba dünya"; liste (harita ("" .join, zip (* [iter (a)] * 4))) sonucu alın ['cehennem', 'o wo'].
truease.com

16
Birisi zip(*[iter(s)]*2)anlamakta zorlanırsa , Python'da nasıl zip(*[iter(s)]*n)çalışır? Başlıklı konuyu okuyun. .
Grijesh Chauhan

15
Bu, tek sayıda karakter içermez, sadece bu karakterleri düşürür: >>> map(''.join, zip(*[iter('01234567')]*5))->['01234']
Bjorn

3
Ayrıca karakterlerin tek sayı işlemek için sadece değiştirmek zip()ile itertools.zip_longest():map(''.join, zip_longest(*[iter(s)]*2, fillvalue=''))
Paulo Freitas

Ayrıca yararlı: dokümanlar içinmaps()
winklerrr

58

Bu itertools sürümü daha kısa ve daha okunabilir olduğunu düşünüyorum:

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

7
ama gerçekten verimli değil: dizelere uygulandığında: çok fazla kopya
Eric

1
Ayrıca seq, itertools versiyonunun ne olduğu için bir jeneratör ise işe yaramaz . OP bunu istemedi, ancak itertool'un versiyonunun o kadar basit olmadığını eleştirmek adil değil.
17:47

25

Bu çözümü beğendim:

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


12

Şu grouper()tarifleri kullanabilirsiniz 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)

Bu işlevler bellek verimlidir ve yinelenebilir özelliklerle çalışır.


6

Aşağıdaki kodu deneyin:

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

Cevabınız OP'nin gereksinimlerini karşılamıyor, yield ''.join(piece)beklendiği gibi çalışması için kullanmanız gerekiyor: 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

Bunu dene:

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

Çıktı:

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

3

Her zamanki gibi, bir astarı sevenler için

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

Ben bir ile Python Fiddle bu çalıştırmak zaman çıktı olarak print(line)olsun this is a line split into n characters. Daha iyi koyarak olabilir misiniz line = [line[i * n:i * n+n] for i,blah in enumerate(line[::n])]? Bunu düzeltin ve iyi bir cevap :).
Google Arama'da

Açıklayabilir misiniz ,blahve neden gerekli? blahHerhangi bir alfa karakteri / karakteriyle yer değiştirebileceğimi , ancak sayıları değiştiremediğimi ve blah/ ve virgülü kaldıramayacağımı fark ettim . Editörüm şu boşlukların eklenmesini öneriyor ,: s
toonarmycaptain

enumerateiki yineleme döndürür, bu yüzden onları koymak için iki yere ihtiyacınız vardır. Ama aslında bu durumda hiçbir şey için ikinci yinelenebilir gerekmez.
Daniel F

1
Alt blahçizgi veya çift alt çizgi kullanmayı tercih etmektense , bkz. Stackoverflow.com/questions/5893163/…
Andy Royal

2

Kısa dize için basit bir özyinelemeli çözüm:

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

print(split('1234567890', 2))

Veya böyle bir formda:

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)

, özyinelemeli yaklaşımda tipik bölme ve fethetme desenini daha açık bir şekilde gösteren (pratik olarak bu şekilde yapılması gerekli değildir)


2

Aynı senaryoya takıldım.

Bu benim için çalıştı

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

Çıktı

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

1

more_itertools.sliceddaha önce bahsedilmişti . İşte more_itertoolskütüphaneden dört seçenek daha :

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

İkinci seçeneklerin her biri aşağıdaki çıktıyı üretir:

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

Tartışılan seçenekleri için Dokümantasyon: grouper, chunked, windowed,split_after


0

Bu basit bir döngü ile elde edilebilir.

a = '1234567890a'
result = []

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

Çıktı ['12', '34', '56', '78', '90', 'a'] gibi görünüyor


2
Bu kod soruyu cevaplayabilirken, bu kodun soruyu neden ve / veya nasıl cevapladığı konusunda ek bağlam sağlamak uzun vadeli değerini arttırır.
βε.εηοιτ.βε

2
Bu, aynı çözümdür: stackoverflow.com/a/59091507/7851470
Georgy
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.