我需要将字符串“ a3b2”解码为“ aaabb”。问题是当数字是两位三位数时。例如。 “ a10b3”应检测到该数字不是不是 1而是10。
我需要开始积累数字。
a = "a12345t5i6o2r43e2"
for i in range(0, len(a)-1):
if a[i].isdigit() is False:
#once i see a letter, i launch a while loop to check how long a digit streak
#after it can be - it's 2,3,4,5 digit number etc
print(a[i])
current_digit_streak = ''
counter = i+1
while a[counter].isdigit(): #this gives index out of range error!
current_digit_streak += a[counter]
counter+=1
如果我将while循环更改为此:
while a[counter].isdigit() and counter < ( len(a)-1)
它确实有效,但是省略了最后一个字母。 我不应该使用正则表达式,而只能使用循环。
答案 0 :(得分:3)
正则表达式非常适合这里。
import re
pat = re.compile(r"""
(\w) # a word character, followed by...
(\d+) # one or more digits""", flags=re.X)
s = "a12345t5i6o2r43e2"
groups = pat.findall(s)
# [('a', '12345'), ('t', '5'), ('i', '6'), ('o', '2'), ('r', '43'), ('e', '2')]
result = ''.join([lett*int(count) for lett, count in groups])
由于某些未知原因,您不能使用正则表达式,因此我建议使用递归函数将字符串分成多个部分。
import itertools
def split_into_groups(s):
if not s:
return []
lett, *rest = s
count, rest = int(itertools.takewhile(str.isdigit, rest)), itertools.dropwhile(str.isdigit, rest)
return [(lett, count)] + split_into_groups(rest)
s = "a12345t5i6o2r43e2"
groups = split_into_groups(s)
result = ''.join([lett*count for lett, count in groups])
,或者使用更通用(且功能派生)的模式:
def unfold(f, x):
while True:
v, x = f(x)
yield v
def get_group(s):
if not s:
raise StopIteration()
lett, *rest = s
count, rest = int(itertools.takewhile(str.isdigit, rest)), itertools.dropwhile(str.isdigit, rest)
return lett*count, rest
s = "a12345t5i6o2r43e2"
result = ''.join(unfold(get_group, s))
答案 1 :(得分:2)
您可以使用groupby:
from itertools import groupby
text = 'a12345t5i6o2r43e2'
groups = [''.join(group) for _, group in groupby(text, key=str.isdigit)]
result = list(zip(groups[::2], groups[1::2]))
print(result)
输出
[('a', '12345'), ('t', '5'), ('i', '6'), ('o', '2'), ('r', '43'), ('e', '2')]
答案 2 :(得分:1)
可能的变体之一
import re
def main():
a = "a10t5i6o2r43e2"
items = re.findall(r'(\w)(\d+)', a)
return ''.join([letter*int(count) for letter, count in items])
答案 3 :(得分:1)
您的for
循环和while
循环使用不同的索引来获取令牌,这就是while
循环再次处理for
循环消耗的字符的原因。相反,您应该使用带有单个索引的while
循环来解析令牌:
a = "a12t5i6o2r11e2"
i = 0
char = repeat = output = ''
while i < len(a):
token = a[i]
if token.isdigit():
repeat += token
if char and repeat and (not token.isdigit() or i == len(a) - 1):
output += char * int(repeat)
char = repeat = ''
if not token.isdigit():
char += token
i += 1
print(output)
这将输出:
aaaaaaaaaaaatttttiiiiiioorrrrrrrrrrree
答案 4 :(得分:1)
这是使用itertools
模块的功能解决方案。您可以使用grouper
recipe from the itertools
docs或通过第三方more_itertools.grouper
导入:
from itertools import groupby
from more_itertools import grouper
from operator import itemgetter
a = "a12t5i6o2r11e2"
it = map(''.join, map(itemgetter(1), groupby(a, key=str.isdigit)))
res = ''.join(char*int(count) for char, count in grouper(it, 2))
'aaaaaaaaaaaatttttiiiiiioorrrrrrrrrrree'
grouper
食谱供参考:
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)
答案 5 :(得分:1)
这有点冗长,但是它可以按照您的要求工作并使用循环:
def parse_segment(string, index):
for i, letter in enumerate(string[index+1:]):
if letter.isalpha():
return string[index+1:i+index+1]
if i + index + 1 >= len(string) - 1:
return string[index+1:]
def segment_string(string):
num_list = []
for index, letter in enumerate(string):
if letter.isalpha():
num_list.append({'letter': letter, 'number': int(parse_segment(string, index))})
return num_list
def list_2_string(list):
ret_string = ''
for row in list:
ret_string += row['letter'] * row['number']
return ret_string
a = "a12345t5i6o2r43e2"
segmented_string = segment_string(a)
result_string = list_2_string(segmented_string)
print(result_string)