Преобразовать строку 5A2B4C11G в [(5,"A"),(2,"B"),(4,"C"),(11,"G")] в Python

Название в значительной степени говорит обо всем. У меня есть небольшой скрипт декодирования длины прогона:

def RLdecode(characterList):
    decodedString = ""
    for character, count in characterList:
        decodedString += character.upper() * count
    return decodedString

Этот сценарий требует список (или что-то еще), который выглядит следующим образом:

[(5,"A"),(2,"B"),(4,"C"),(11,"G")]

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

"5A2B4C11G"

Как мне преобразовать строку, подобную приведенной выше, в список, читаемый моим сценарием? Кроме того, извините, что название вопроса очень конкретное, но я не знаю, как называется этот процесс:\

5 ответов

Решение

с помощью itertools.groupby :

Есть хороший способ сделать группировку букв / цифр, используя itertools.groupby:

import itertools
a="5A2B4C11G"
result = [("".join(v)) for k,v in itertools.groupby(a,str.isdigit)]

это возвращает ['5', 'A', '2', 'B', '4', 'C', '11', 'G']

К сожалению, это выравнивает число / букву кортежа, поэтому требуется больше работы. Обратите внимание, что применение решения Каушика к этому вводу дает ожидаемый результат теперь, когда число / буква выполнены правильно:

[(int(result[i]),result[i+1]) for i in range(0,len(result),2)]

результат:

[(5, 'A'), (2, 'B'), (4, 'C'), (11, 'G')]

используя регулярные выражения:

В любом случае, в этом случае регулярные выражения хорошо подходят для извлечения шаблонов с необходимой иерархией.

Просто сопоставьте строку, используя 1 или более цифр + букву, и преобразуйте полученные кортежи в формат (целое число, строка), используя для этого понимание списка, в одну строку.

import re
a="5A2B4C11G"

result = [(int(i),v) for i,v in re.findall('(\d+)([A-Z])',a)]

print(result)

дает:

[(5, 'A'), (2, 'B'), (4, 'C'), (11, 'G')]

С помощью list comprehension:

#s is the string
[(int(s[i]),s[i+1]) for i in range(0,len(s),2)]

# значения драйвера

IN : s="5A2B4C"
OUT : [(5, 'A'), (2, 'B'), (4, 'C')]

Вот range(0,len(s),2) дает значения как: [0, 2, 4] который мы используем, чтобы пройти через string,

ПРИМЕЧАНИЕ: этот курс работает только со строками even размер и с номерами ниже 10.

РЕДАКТИРОВАТЬ: Что касается чисел с двузначными числами, ответ Жан-Франсуа Фабр работает хорошо.

Вы уже получили ответ от Жан-Франсуа Фабра. Процесс декодирования длины вызова.

Весь процесс может быть выполнен в один лайнер с помощью следующего кода.

from re import sub
text = "5A2B4C11G"
sub(r'(\d+)(\D)', lambda m: m.group(2) * int(m.group(1)),text)

OUTPUT : 'AAAAABBCCCCGGGGGGGGGGG'

П р и м е ч а н и е - Это не ответ, а просто идея оптимизации для ОП, так как ответ уже есть в Жан-Франсуа Фабре.

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

В одну строку

sorted_list=[i for i in re.findall(pattern, a, re.M)]

Тот же подход:

import re
a="5A2B4C"

pattern=r'(\d)(\w)'
list=[]
art=re.findall(pattern,a,re.M)

for i in art:
    list.append(i)

print(list)

Для вашей новой отредактированной проблемы вот мое новое решение:

import re

a = "5A2B4C11G"

pattern = r'([0-9]+)([a-zA-Z])'
list = []
art = re.findall(pattern, a, re.M)

for i in art:
    list.append(i)

print(list)

Выход:

[('5', 'A'), ('2', 'B'), ('4', 'C'), ('11', 'G')]
import re

str = "5A2B4C11G"

pattern = r"(\d+)(\D)"                        # group1: digit(s), group2: non-digit
substitution = r"\1,\2 "                      # "ditits,nondigit "

temp = re.sub(pattern, substitution, str)     # gives "5,A 2,B 4,C 11,G "
temp = temp.split()                           # gives ['5,A', '2,B', '4,C', '11,G']
result = [el.split(",") for el in temp]       # gives [['5', 'A'], ['2', 'B'],
                                              #       ['4', 'C'], ['11', 'G']] - see note

Сначала мы заменим последовательности digits с последующим symbol к чему-то, к чему мы можем применить 2-х уровневый split() выбирая 2 разных разделителя в строке замены r"\1,\2 "

  • space для первого уровня (внешнего) split(), и
  • , для 2- го уровня один (внутренний).

Затем мы применяем эти 2 раскола.

Примечание: если у вас есть веские основания для получения tuples (вместо достаточно хорошего внутреннего lists), просто примените tuple() Функция в последнем утверждении:

     result = [tuple(el.split(",")) for el in temp]
Другие вопросы по тегам