Разделить строку на каждый n-й символ?


383

Можно ли разбить строку на каждый n-й символ?

Например, предположим, у меня есть строка, содержащая следующее:

'1234567890'

Как я могу заставить это выглядеть так:

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

Ответы:


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

35
Это действительно отличный ответ, потому что он не запутан в любом случае, и этот факт позволяет легко запомнить метод из-за его простоты
Тревор Рудольф

1
@TrevorRudolph Это делает только то, что вы говорите. Приведенный выше ответ на самом деле является всего лишь циклом for, но выражается в виде питона. Кроме того, если вам нужно запомнить «упрощенный» ответ, есть как минимум сотни тысяч способов запомнить их: начальная страница в стеке; копирование, а затем вставка в электронную почту; хранение «полезного» файла с вещами, которые вы хотите запомнить; просто используя современный поисковик, когда вам что-то нужно; использование закладок (возможно) в каждом веб-браузере; и т. д.
14:03

1
На втором , хотя, кажется , как будто вы находитесь серьезно. Я действительно надеюсь, что вы серьезно, так как это действительно не запутано.
dylnmc

1
я был серьезен, я использовал этот код в своем двоичном конвертере в эмуляторе, мне понравилось, что это был pythonic для loop haaha, но спасибо за дальнейшее объяснение, почему мне нравится этот метод!
Тревор Рудольф

5
По иронии судьбы, попытка использовать слова так, чтобы они не имели скрытого значения, часто приводят к запутанным предложениям.
deed02392

208

Просто чтобы быть полным, вы можете сделать это с помощью регулярного выражения:

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

Для нечетного числа символов вы можете сделать это:

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

Вы также можете сделать следующее, чтобы упростить регулярное выражение для длинных кусков:

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

И вы можете использовать, re.finditerесли строка длинная, чтобы генерировать чанк по чанку.


3
Это, безусловно, лучший ответ здесь и заслуживает того, чтобы быть на вершине. Можно даже написать, '.'*nчтобы было понятнее. Нет соединения, нет застегивания, нет петель, нет понимания списка; просто найдите следующие два символа рядом друг с другом, что именно так думает человеческий мозг. Если бы Монти Пайтон был еще жив, ему бы понравился этот метод!
jdk1.0

Это самый быстрый метод и для достаточно длинных струн: gitlab.com/snippets/1908857
Ральф Болтон,

Это не будет работать, если строка содержит символы новой строки. Это необходимо flags=re.S.
Аран-Фей

аааа ... регулярное выражение .... почему я не подумал об этом XD
Мистер PizzaGuy

148

Для этого в Python уже есть встроенная функция.

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

Вот что говорит документация для упаковки:

>>> 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)) разбивает строку на группы по 3 цифры, но начинается спереди, а не сзади. Результат: ['123', '456', '78']
Atalanttore

2
Интересно узнать о «обтекании», но он не делает именно то, что было сказано выше. Он больше ориентирован на отображение текста, чем на разбиение строки на фиксированное количество символов.
Орен

2
wrapможет не вернуть то, что запрашивается, если строка содержит пробел. например, wrap('0 1 2 3 4 5', 2)возвращается ['0', '1', '2', '3', '4', '5'](элементы удалены)
satomacoto

3
Это действительно отвечает на вопрос, но что произойдет, если есть пробелы, и вы хотите, чтобы они содержались в разделенных символах? wrap () удаляет пробелы, если они выпадают сразу после разделенной группы символов
Железный прокурор

1
Это работает плохо, если вы хотите разделить текст с дефисами (число, которое вы даете в качестве аргумента, на самом деле является МАКСИМАЛЬНЫМ числом символов, а не точным, и оно разбивается, т. Е. На дефисы и пробелы).
MrVocabulary

81

Еще один распространенный способ группировки элементов в группы n-длины:

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

Этот метод идет прямо из документов для zip().


2
В [19]: a = "Привет, мир"; list (map ("" .join, zip (* [iter (a)] * 4))) получить результат ['hell', 'o wo'].
truease.com

16
Если кто-то считает zip(*[iter(s)]*2)сложным для понимания, прочитайте, Как zip(*[iter(s)]*n)работает в Python? ,
Грижеш Чаухан

15
Это не учитывает нечетное количество символов, оно просто отбрасывает эти символы: >>> map(''.join, zip(*[iter('01234567')]*5))->['01234']
Bjorn

3
Чтобы также обрабатывать нечетное число символов, просто замените zip()на itertools.zip_longest():map(''.join, zip_longest(*[iter(s)]*2, fillvalue=''))
Пауло Фрейтас

Также полезно: документы дляmaps()
winklerrr

58

Я думаю, что это короче и более читабельно, чем версия 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
Он также не работает , если след является генератором, который является то , что версия itertools является для . Не то чтобы OP просил об этом, но было бы несправедливо критиковать версию itertool не так просто.
CryingCyclops

25

Мне нравится это решение:

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


12

Вы можете использовать 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)

Эти функции экономят память и работают с любыми итерациями.


6

Попробуйте следующий код:

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)его, чтобы он работал должным образом
Пауло Фрейтас

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

Попробуй это:

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

Вывод:

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

3

Как всегда, для тех кто любит лайнеры

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любым альфа-символом / символами, но не цифрами, и не могу удалить blahзапятую или / или. Мой редактор предлагает добавить пробел после ,: s
toonarmycaptain

enumerateвозвращает два итерируемых элемента, поэтому для их размещения необходимо два места. Но вам на самом деле не нужна вторая итерация для чего-либо в этом случае.
Даниэль Ф

1
Вместо того, чтобы blahпредпочитать использовать подчеркивание или двойное подчеркивание, см .: stackoverflow.com/questions/5893163/…
Andy Royal

2

Простое рекурсивное решение для короткой строки:

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)

, который более подробно иллюстрирует типичную модель «разделяй и властвуй» в рекурсивном подходе (хотя практически нет необходимости делать это таким образом)


2

Я застрял в том же сценарии.

Это сработало для меня

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

1

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


0

Это может быть достигнуто простым циклом for.

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
Георгий
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.