Преобразовать строку 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]