Как распаковать последовательность букв и чисел в строку?
Мне с помощью кода нужно превратить из A3b4 => AAAbbbb.
Это был мой простой пример, но в задании ввод гораздо больше.
Вот пример моего кода:
i = 0
my_letters = []
my_numbers = []
numbers = '0123456789'
letters = 'qwertyuiopasdfghjklzxcvbnm'
up_letters = 'QWERTYUIOPASDFGHJKLZXCVBNM'
with open(r"dataset_3363_2 (1).txt") as s:
for row in s:
opened_string = row
for i in range(len(opened_string) - 1):
if opened_string[i] in letters or opened_string[i] in up_letters:
my_letters.append(opened_string[i])
elif opened_string[i] in numbers:
my_numbers.append(opened_string[i])
if opened_string[i+1] in numbers:
my_numbers[i].append(opened_string[i + 1])
print(my_letters)
print(my_numbers)
s.close()
В dataset_3363_2 (1).txt читается
"q20j13h11Z6N8v7z17E12U4L1u2P18c10J17B4j2W5H20m20u8U10D4k18T15u9h12"
Главная моя проблема - когда код записал в отдельный список букву, а потом считывает цифру, он находит лишь ОДНУ цифру, а мне может пригодится число 15, а мой код считает это как 1 и 5.
Главная моя задумка - найти буквы, и записать их в список, потом найти цифры, и записать их в другой список. А потом умножать букву my_letter[i] * my_numbers[i] (i = 0 а потом увеличивается на одну единицу)
Если же я плохо смог объяснить, то вот оригинал задания.
Ответы (5 шт):
Воспользуйтесь регулярными выражениями:
import re
def unpack(s):
res = ""
for x in re.findall(r"(\w)(\d+)", s):
res += x[0] * int(x[1])
return res
однострочник:
res = "".join([c * int(n) for c,n in re.findall(r"(\w)(\d+)", s)])
Решение на "Vanilla Python":
def unpack(s):
res = ""
curr_c = ""
n = 0
for i,c in enumerate(s):
if c.isalpha():
curr_c = c
n = 0
elif c.isdigit():
n = n*10 + int(c)
if i == len(s)-1 or not s[i+1].isdigit():
res += curr_c * n
return res
Тесты:
In [80]: unpack("A10b4")
Out[80]: 'AAAAAAAAAAbbbb'
In [81]: unpack("A1B2")
Out[81]: 'ABB'
В принципе, вы выбрали верный подход к решению задачи. Если не использовать регулярные выражения и следовать вашему алгоритму, то сделать можно так:
a = "q20j13h11Z6N8v7z17E12U4L1u2P18c10J17B4j2W5H20m20u8U10D4k18T15u9h12"
#получаем два списка - один с буквами, другой с числами, но в обратном порядке
def separate(a: str):
letters = []
muls = []
while a:
head = a.rstrip('0123456789')
tail = a[len(head):]
muls.append(tail)
letters.append(head[-1])
a = head[:-1]
return (letters, muls)
# перемножаем список с буквами на список с числами в соответствующих позициях
def mult(letters:list, muls:list):
res =""
for i in range(len(letters)):
res+=letters[i]*int(muls[i])
return res[::-1] # переворачиваем строку в нужном порядке
letters, muls = separate(a)
#print(letters)
#['h', 'u', 'T', 'k', 'D', 'U', 'u', 'm', 'H', 'W', 'j', 'B', 'J', 'c', 'P', 'u', 'L', 'U', 'E', 'z', 'v', 'N', 'Z', 'h', 'j', 'q']
#print(muls)
#['12', '9', '15', '18', '4', '10', '8', '20', '20', '5', '2', '4', '17', '10', '18', '2', '1', '4', '12', '17', '7', '8', '6', '11', '13', '20']
result = mult(letters, muls)
print(result)
qqqqqqqqqqqqqqqqqqqqjjjjjjjjjjjjjhhhhhhhhhhhZZZZZZNNNNNNNNvvvvvvvzzzzzzzzzzzzzzzzzEEEEEEEEEEEEUUUULuuPPPPPPPPPPPPPPPPPPccccccccccJJJJJJJJJJJJJJJJJBBBBjjWWWWWHHHHHHHHHHHHHHHHHHHHmmmmmmmmmmmmmmmmmmmmuuuuuuuuUUUUUUUUUUDDDDkkkkkkkkkkkkkkkkkkTTTTTTTTTTTTTTTuuuuuuuuuhhhhhhhhhhhh
Если я не ошибаюсь, это решение будет быстрее, чем решение с использованием регулярных выражений и с проверками isalpha/isnumeric. Причем, ощутимо быстрее.
Если использовать регулярки, то можно через замену re.sub еще в одну строку
import re
text = "q20j13h11Z6N8v7z17E12U4L1u2P18c10J17B4j2W5H20m20u8U10D4k18T15u9h12"
print(re.sub('(\D)(\d+)', lambda x: x.group(1) * int(x.group(2)), text))
Асимптотически минимальное решение:
a = "q20j13h11Z6N8v7z17E12U4L1u2P18c10J17B4j2W5H20m20u8U10D4k18T15u9h12"
s = ''
d = 0
cur_s = ''
def is_digit(s):
for i in '0123456789':
if i == s:
return True
return False
for i in range(len(a)):
if is_digit(a[i]):
d*=10
d+=int(a[i])
else:
s+= cur_s*d
d=0
cur_s = a[i]
s+=cur_s*d
print(s)```