Chia chuỗi mỗi ký tự thứ n?


382

Có thể phân tách một chuỗi mỗi ký tự thứ n?

Ví dụ: giả sử tôi có một chuỗi chứa như sau:

'1234567890'

Làm thế nào tôi có thể làm cho nó trông như thế này:

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

Câu trả lời:


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

35
Đây là một câu trả lời thực sự tuyệt vời bởi vì nó không bị sai lệch theo bất kỳ cách nào và thực tế đó cho phép bạn nhớ phương pháp dễ dàng do tính đơn giản của nó
Trevor Rudolph

1
@TrevorRudolph Nó chỉ thực hiện chính xác những gì bạn nói với nó. Câu trả lời ở trên thực sự chỉ là một vòng lặp for nhưng được thể hiện một cách trăn trở. Ngoài ra, nếu bạn cần nhớ một câu trả lời "đơn giản", có ít nhất hàng trăm ngàn cách để nhớ chúng: đánh dấu sao vào trang trên stackoverflow; sao chép và sau đó dán vào một email; giữ một tập tin "hữu ích" với những thứ bạn muốn nhớ; chỉ cần sử dụng một công cụ tìm kiếm hiện đại bất cứ khi nào bạn cần một cái gì đó; sử dụng dấu trang trong (có thể) mọi trình duyệt web; vv
dylnmc

1
Trên mặc dù thứ hai, nó xuất hiện như thể bạn nghiêm trọng. Tôi thực sự hy vọng bạn nghiêm túc vì nó thực sự không phức tạp.
dylnmc

1
Tôi đã rất nghiêm túc, tôi đã sử dụng mã này trong trình chuyển đổi nhị phân của mình trong một trình giả lập, tôi thích rằng nó là một pythonic cho vòng lặp haaha nhưng cảm ơn vì đã phá vỡ thêm tại sao tôi thích phương pháp này!
Trevor Rudolph

5
Trớ trêu thay, cố gắng sử dụng các từ theo cách không có ý nghĩa ẩn, thường sẽ dẫn đến các câu phức tạp.
deed02392

208

Chỉ cần hoàn thành, bạn có thể làm điều này với biểu thức chính quy:

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

Đối với số lượng ký tự lẻ bạn có thể làm điều này:

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

Bạn cũng có thể làm như sau, để đơn giản hóa regex cho các đoạn dài hơn:

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

Và bạn có thể sử dụng re.finditernếu chuỗi dài để tạo chunk bằng chunk.


3
Đây là câu trả lời tốt nhất ở đây và xứng đáng đứng đầu. Một thậm chí có thể viết '.'*nđể làm cho nó rõ ràng hơn. Không tham gia, không nén, không vòng lặp, không hiểu danh sách; chỉ cần tìm hai nhân vật tiếp theo cạnh nhau, đó chính xác là cách bộ não con người nghĩ về nó. Nếu Monty Python vẫn còn sống, anh ấy sẽ thích phương pháp này!
jdk1.0

Đây cũng là phương pháp nhanh nhất cho các chuỗi dài hợp lý: gitlab.com/snippets/1908857
Ralph Bolton

Điều này sẽ không hoạt động nếu chuỗi chứa dòng mới. Điều này cần flags=re.S.
Aran-Fey

ahhh .... regex .... tại sao tôi không nghĩ về XD đó
Mr PizzaGuy

148

Đã có một chức năng sẵn có trong python cho việc này.

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

Đây là những gì các chuỗi để bọc nói:

>>> 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 (quấn ('12345678', 3)) chia chuỗi thành các nhóm gồm 3 chữ số, nhưng bắt đầu ở phía trước và không phía sau. Kết quả: ['123', '456', '78']
Atalanttore

2
Thật thú vị khi tìm hiểu về 'bọc' nhưng nó không thực hiện chính xác những gì được hỏi ở trên. Nó thiên về hướng hiển thị văn bản hơn là chia một chuỗi thành một số ký tự cố định.
Oren

2
wrapcó thể không trả về những gì được yêu cầu nếu chuỗi chứa khoảng trắng. ví dụ wrap('0 1 2 3 4 5', 2)trả về ['0', '1', '2', '3', '4', '5'](các phần tử bị tước)
satomacoto

3
Điều này thực sự trả lời câu hỏi, nhưng điều gì xảy ra nếu có khoảng trắng và bạn muốn chúng được duy trì trong các ký tự phân tách? quấn () loại bỏ khoảng trắng nếu chúng rơi thẳng sau một nhóm nhân vật bị chia tách
Luật sư Iron

1
Điều này hoạt động kém nếu bạn muốn phân tách văn bản bằng dấu gạch nối (số bạn đưa ra làm đối số thực sự là số lượng ký tự TỐI ĐA, không chính xác, và nó phá vỡ tức là trên dấu gạch ngang và khoảng trắng).
MrVocellect

81

Một cách phổ biến khác để nhóm các yếu tố thành các nhóm có độ dài n:

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

Phương pháp này xuất phát trực tiếp từ các tài liệu cho zip().


2
Trong [19]: a = "xin chào thế giới"; list (map ("" .join, zip (* [iter (a)] * 4))) nhận kết quả ['hell', 'o wo'].
truease.com

16
Nếu ai đó thấy zip(*[iter(s)]*2)khó hiểu, hãy đọc Làm thế nào để zip(*[iter(s)]*n)làm việc trong Python? .
Grijesh Chauhan

15
Điều này không chiếm số lượng ký tự lẻ, nó chỉ đơn giản là bỏ các ký tự đó: >>> map(''.join, zip(*[iter('01234567')]*5))->['01234']
Bjorn

3
Để xử lý số ký tự lẻ, chỉ cần thay thế zip()bằng itertools.zip_longest():map(''.join, zip_longest(*[iter(s)]*2, fillvalue=''))
Paulo Freitas

Cũng hữu ích: tài liệu chomaps()
winklerrr

58

Tôi nghĩ rằng nó ngắn hơn và dễ đọc hơn phiên bản 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
nhưng không thực sự hiệu quả: khi áp dụng cho chuỗi: quá nhiều bản sao
Eric

1
Nó cũng không hoạt động nếu seq là một trình tạo, đó là phiên bản itertools dành cho . Không phải OP yêu cầu điều đó, nhưng thật không công bằng khi chỉ trích phiên bản của itertool không đơn giản như vậy.
CryingCyclops

25

Tôi thích giải pháp này:

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


12

Bạn có thể sử dụng grouper()công thức từ 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)

Các chức năng này là bộ nhớ hiệu quả và làm việc với bất kỳ iterables nào.


6

Hãy thử đoạn mã sau:

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

Câu trả lời của bạn không đáp ứng yêu cầu của OP, bạn phải sử dụng yield ''.join(piece)để làm cho nó hoạt động như mong đợi: 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

Thử cái này:

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

Đầu ra:

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

3

Như mọi khi, cho những người yêu thích một lớp lót

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

Khi tôi chạy cái này trong Python Fiddle với đầu ra print(line)tôi nhận được this is a line split into n characters. Bạn có thể tốt hơn đặt : line = [line[i * n:i * n+n] for i,blah in enumerate(line[::n])]? Khắc phục điều này và đó là một câu trả lời tốt :).
Có gì trong Tìm kiếm của Google

Bạn có thể giải thích ,blahvà tại sao nó cần thiết? Tôi nhận thấy tôi có thể thay thế blahbằng bất kỳ ký tự alpha nào, nhưng không phải số và không thể xóa blahhoặc / và dấu phẩy. Trình chỉnh sửa của tôi đề nghị thêm khoảng trắng sau ,: s
toonarmycaptain

enumeratetrả về hai lần lặp, vì vậy bạn cần hai nơi để đặt chúng. Nhưng bạn không thực sự cần lần lặp thứ hai cho bất cứ điều gì trong trường hợp này.
Daniel F

1
Thay vì blahtôi thích sử dụng dấu gạch dưới hoặc dấu gạch dưới gấp đôi, hãy xem: stackoverflow.com/questions/5893163/ Kẻ
Andy Royal

2

Một giải pháp đệ quy đơn giản cho chuỗi ngắn:

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

print(split('1234567890', 2))

Hoặc ở dạng như vậy:

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)

, minh họa mô hình phân chia và chinh phục điển hình theo cách tiếp cận đệ quy rõ ràng hơn (mặc dù thực tế không cần thiết phải làm theo cách này)


2

Tôi đã bị mắc kẹt trong cùng một phối cảnh.

Điều này làm việc cho tôi

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

Đầu ra

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

1

more_itertools.slicedđã được đề cập trước đó. Dưới đây là bốn tùy chọn khác từ more_itertoolsthư viện:

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

Mỗi tùy chọn sau tạo ra đầu ra sau:

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

Tài liệu cho các tùy chọn thảo luận: grouper, chunked, windowed,split_after


0

Điều này có thể đạt được bằng một vòng lặp đơn giản.

a = '1234567890a'
result = []

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

Đầu ra trông giống như ['12', '34', '56', '78', '90', 'a']


2
Mặc dù mã này có thể trả lời câu hỏi, cung cấp ngữ cảnh bổ sung về lý do và / hoặc cách mã này trả lời câu hỏi cải thiện giá trị lâu dài của nó.
β.οιτ.

2
Đây là giải pháp tương tự như ở đây: stackoverflow.com/a/59091507/7851470
Georgy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.