如何在字符串中累积数字序列并将其转换为一个数字?

时间:2018-11-27 16:54:37

标签: python string

我需要将字符串“ 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)

它确实有效,但是省略了最后一个字母。 我不应该使用正则表达式,而只能使用循环。

6 个答案:

答案 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)