แยกสตริงทุกอักขระที่ n หรือไม่


380

เป็นไปได้ไหมที่จะแบ่งสตริงทุกอักขระที่ n?

ตัวอย่างเช่นสมมติว่าฉันมีสตริงที่มีสิ่งต่อไปนี้:

'1234567890'

ฉันจะทำให้มันเป็นแบบนี้ได้อย่างไร:

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

คำตอบ:


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

35
นี่เป็นคำตอบที่ยอดเยี่ยมจริง ๆ เพราะมันไม่ซับซ้อนในทางใดทางหนึ่งและความจริงช่วยให้คุณสามารถจดจำวิธีการได้อย่างง่ายดายเนื่องจากความเรียบง่าย
Trevor Rudolph

1
@TrevorRudolph มันทำในสิ่งที่คุณบอกเท่านั้น คำตอบข้างต้นเป็นเพียงการวนรอบ แต่แสดงแบบไพ ธ อน นอกจากนี้หากคุณจำเป็นต้องจดจำคำตอบ "แบบง่าย" มีอย่างน้อยหลายร้อยวิธีในการจดจำพวกเขา: นำหน้าใน stackoverflow; คัดลอกแล้ววางลงในอีเมล เก็บไฟล์ "ประโยชน์" ไว้กับสิ่งที่คุณต้องการจดจำ เพียงใช้เครื่องมือค้นหาที่ทันสมัยเมื่อใดก็ตามที่คุณต้องการ ใช้บุ๊กมาร์กใน (อาจ) ทุกเว็บเบราว์เซอร์ ฯลฯ
dylnmc

1
ในวินาทีที่ดูเหมือนว่าคุณจะร้ายแรง ฉันหวังว่าคุณจะจริงจังเพราะมันไม่ได้ซับซ้อนจริง ๆ
dylnmc

1
ฉันจริงจังฉันใช้รหัสนี้ในตัวแปลงเลขฐานสองของฉันในโปรแกรมจำลองฉันชอบที่มันเป็น pythonic สำหรับ loop haaha แต่ขอบคุณสำหรับการทำลายต่อไปทำไมฉันสนุกกับวิธี!
เทรเวอร์รูดอล์ฟ

5
กระแทกแดกดันพยายามที่จะใช้คำในลักษณะที่จะไม่มีความหมายที่ซ่อนอยู่มักจะส่งผลให้ประโยคที่ซับซ้อน
deed02392

207

เพื่อให้เสร็จสมบูรณ์คุณสามารถทำได้ด้วย regex:

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

สำหรับจำนวนตัวอักษรคี่คุณสามารถทำสิ่งนี้:

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

คุณยังสามารถทำสิ่งต่อไปนี้เพื่อทำให้ regex ง่ายขึ้นสำหรับชิ้นส่วนที่ยาวกว่า:

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

และคุณสามารถใช้re.finditerถ้าสตริงมีความยาวในการสร้างชิ้นโดยชิ้น


3
นี่คือคำตอบที่ดีที่สุดที่นี่และสมควรที่จะอยู่ด้านบน ใครสามารถเขียน'.'*nเพื่อให้ชัดเจนยิ่งขึ้น ไม่มีการเข้าร่วมไม่มีซิปไม่มีลูปไม่มีรายการเข้าใจ เพียงแค่ค้นหาตัวละครสองตัวถัดไปซึ่งอยู่ติดกันซึ่งเป็นสิ่งที่สมองมนุษย์คิด หาก Monty Python ยังมีชีวิตอยู่เขาจะชอบวิธีนี้!
jdk1.0

นี่เป็นวิธีที่เร็วที่สุดสำหรับสตริงที่ยาวพอสมควรเช่นกัน: gitlab.com/snippets/1908857
Ralph Bolton

สิ่งนี้จะไม่ทำงานหากสตริงมีการขึ้นบรรทัดใหม่ ความต้องการflags=re.Sนี้
Aran-Fey

ahhh .... regex .... ทำไมฉันไม่คิด XD นั้น
Mr PizzaGuy

147

มีฟังก์ชั่น inbuilt ในหลามสำหรับสิ่งนี้

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

นี่คือสิ่งที่ docstring สำหรับการตัดพูดว่า:

>>> 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
พิมพ์ (wrap ('12345678', 3)) แยกสตริงออกเป็นกลุ่มตัวเลข 3 หลัก แต่เริ่มที่ด้านหน้าและไม่อยู่ด้านหลัง ผลลัพธ์: ['123', '456', '78']
Atalanttore

2
เป็นที่น่าสนใจที่จะเรียนรู้เกี่ยวกับ 'ห่อ' แต่ก็ไม่ได้ทำสิ่งที่ถามไว้ข้างต้น มันมุ่งเน้นไปที่การแสดงข้อความมากกว่าการแยกสตริงเป็นจำนวนอักขระที่แน่นอน
Oren

2
wrapอาจไม่ส่งคืนสิ่งที่ถูกถามถ้าสตริงมีช่องว่าง เช่นwrap('0 1 2 3 4 5', 2)ผลตอบแทน['0', '1', '2', '3', '4', '5'](องค์ประกอบถูกปล้น)
satomacoto

3
สิ่งนี้จะตอบคำถามได้ แต่จะเกิดอะไรขึ้นถ้ามีช่องว่างและคุณต้องการให้อักขระนั้นอยู่ในอักขระแยก wrap () ลบช่องว่างหากตรงตามกลุ่มของอักขระ
Iron Attorney

1
วิธีนี้ใช้งานได้ไม่ดีหากคุณต้องการแยกข้อความด้วยเครื่องหมายยัติภังค์ (ตัวเลขที่คุณให้เป็นอาร์กิวเมนต์คือจำนวนอักขระสูงสุดจริงไม่ใช่ตัวอักษรที่แน่นอน
MrVocabulary

80

อีกวิธีการทั่วไปของการจัดกลุ่มองค์ประกอบเป็นกลุ่มความยาว n:

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

zip()วิธีการนี้มาตรงจากเอกสารสำหรับ


2
ใน [19]: a = "hello world"; รายการ (แผนที่ ("" .join, zip (* [iter (a)] * 4))) รับผลลัพธ์ ['hell', 'o wo']
truease.com

16
ถ้ามีคนพบว่าzip(*[iter(s)]*2)เรื่องยุ่งยากที่จะเข้าใจอ่านอย่างไรzip(*[iter(s)]*n)ในการทำงานในงูใหญ่? .
Grijesh Chauhan

15
นี่ไม่ใช่บัญชีสำหรับจำนวนคี่ที่แปลกประหลาดมันก็จะทิ้งตัวอักษรเหล่านั้น: >>> map(''.join, zip(*[iter('01234567')]*5))->['01234']
Bjorn

3
หากต้องการจัดการกับจำนวนตัวอักษรแปลก ๆ ให้แทนที่zip()ด้วยitertools.zip_longest():map(''.join, zip_longest(*[iter(s)]*2, fillvalue=''))
Paulo Freitas

มีประโยชน์ด้วย: docs สำหรับmaps()
winklerrr

57

ฉันคิดว่านี่สั้นและอ่านง่ายกว่ารุ่น 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)))

7
แต่ไม่มีประสิทธิภาพจริง ๆ : เมื่อใช้กับสตริง: มีสำเนามากเกินไป
เอริค

1
นอกจากนี้ยังไม่ทำงานถ้า seq เป็นเครื่องกำเนิดไฟฟ้าซึ่งเป็นสิ่งที่รุ่น itertools เป็นสำหรับ ไม่ใช่ OP ที่ขอสิ่งนั้น แต่มันไม่ยุติธรรมเลยที่จะวิพากษ์วิจารณ์เวอร์ชั่นของ itertool ไม่ใช่เรื่องง่าย
CryingCyclops



11

คุณสามารถใช้grouper()สูตรจาก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)

ฟังก์ชั่นเหล่านี้มีหน่วยความจำที่มีประสิทธิภาพและทำงานกับ iterables ใด ๆ


5

ลองรหัสต่อไปนี้:

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

คำตอบของคุณไม่เป็นไปตามข้อกำหนดของ OP คุณต้องใช้yield ''.join(piece)เพื่อให้ทำงานตามที่คาดไว้: eval.in/813878
Paulo Freitas

4
>>> 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']


2

เช่นเคยสำหรับผู้ที่รักหนึ่งสมุทร

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

เมื่อฉันเรียกใช้สิ่งนี้ใน Python Fiddle โดยที่print(line)ฉันได้this is a line split into n charactersผลลัพธ์เป็น คุณอาจจะดีกว่าการวาง: line = [line[i * n:i * n+n] for i,blah in enumerate(line[::n])]? แก้ไขปัญหานี้และเป็นคำตอบที่ดี :)
มีอะไรในการค้นหาของ Google

คุณช่วยอธิบาย,blahได้หรือไม่และทำไมจึงจำเป็น ฉันสังเกตเห็นว่าฉันสามารถแทนที่blahด้วยตัวอักษร / s ตัวใดตัวหนึ่ง แต่ไม่ใช่ตัวเลขและไม่สามารถลบblahหรือ / และเครื่องหมายจุลภาค บรรณาธิการของฉันแนะนำให้เพิ่มช่องว่างหลังจาก,: s
toonarmycaptain

enumerateส่งกลับสองค่า iterables ดังนั้นคุณต้องสองสถานที่เพื่อวาง แต่คุณไม่ต้องการการทำซ้ำครั้งที่สองสำหรับทุกสิ่งในกรณีนี้
Daniel F

1
มากกว่าที่blahฉันต้องการใช้ขีดเส้นใต้หรือขีดเส้นใต้คู่ดู: stackoverflow.com/questions/5893163/…
Andy Royal

1

โซลูชันแบบเรียกซ้ำง่ายๆสำหรับสตริงแบบสั้น:

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

print(split('1234567890', 2))

หรือในรูปแบบดังกล่าว:

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)

ซึ่งแสดงให้เห็นถึงรูปแบบการแบ่งแยกและพิชิตโดยทั่วไปในแนวทางแบบวนซ้ำอย่างชัดเจนยิ่งขึ้น (แม้ว่าจะไม่จำเป็นต้องทำแบบนี้)


1

ฉันติดอยู่ใน Scenrio เดียวกัน

สิ่งนี้ใช้ได้สำหรับฉัน

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

เอาท์พุต

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

0

more_itertools.slicedได้รับการกล่าวถึงก่อน ที่นี่มีสี่ตัวเลือกเพิ่มเติมจากmore_itertoolsห้องสมุด:

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

แต่ละตัวเลือกหลังผลิตผลลัพธ์ต่อไปนี้:

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

เอกสารสำหรับตัวเลือกที่กล่าวถึง: grouper, chunked, windowed,split_after


-1

สามารถทำได้โดยง่ายสำหรับการวนซ้ำ

a = '1234567890a'
result = []

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

ผลลัพธ์ดูเหมือนว่า ['12', '34', '56', '78', '90', 'a']


2
ในขณะที่รหัสนี้อาจตอบคำถาม แต่มีบริบทเพิ่มเติมเกี่ยวกับสาเหตุและ / หรือวิธีการที่รหัสนี้ตอบคำถามช่วยปรับปรุงมูลค่าระยะยาว
β.εηοιτ.βε

2
นี่เป็นโซลูชันเดียวกับที่นี่: stackoverflow.com/a/59091507/7851470
Georgy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.