将 5A2B4C11G 字符串转换为 [(5,"A"),(2,"B"),(4,"C"),(11,"G")] in Python

Convert 5A2B4C11G string to [(5,"A"),(2,"B"),(4,"C"),(11,"G")] in Python

标题几乎说明了一切。我有一个小的run-length解码脚本:

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

该脚本需要一个如下所示的列表(或其他任何内容):

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

但是为了让它更user-friendly,我希望用户能够输入这样的字符串:

"5A2B4C11G"

如何将上面的字符串转换为我的脚本可读的列表?另外,抱歉,问题的标题很具体,但我不知道这个过程叫什么:\

使用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 的数字。

编辑: 至于两位数的数字, 的答案很好。

如果需要,您可以使用正则表达式执行此操作:

In one line

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)

Output:

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

使用 itertools.groupby:

有一个很好的方法可以使用 itertools.groupby:

进行 letter/digit 分组
import itertools
a="5A2B4C11G"
result = [("".join(v)) for k,v in itertools.groupby(a,str.isdigit)]

那个returns['5', 'A', '2', 'B', '4', 'C', '11', 'G']

不幸的是,它使 number/letter 元组变平,因此需要做更多的工作。请注意,现在 number/letter 已正确完成,将 Kaushik 解决方案应用于该输入会产生预期结果:

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

结果:

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

使用正则表达式:

无论如何,在那种情况下,正则表达式非常适合提取具有所需层次结构的模式。

只需使用 1 个或多个数字 + 一个字母来匹配字符串,并将获得的元组转换为匹配 (integer, string) 格式,使用列表理解在一行中这样做。

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')]

您已经从那里得到了答案。 这个过程就是调用长度解码。

整个过程可以通过以下代码在一个线程中完成。

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

OUTPUT : 'AAAAABBCCCCGGGGGGGGGGG'

注意 这不是答案,只是 OP 的优化想法,因为答案已经存在于

import re

str = "5A2B4C11G"

pattern = r"(\d+)(\D)"                        # group1: digit(s), group2: non-digit
substitution = r", "                      # "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", "

  • space 用于第 1st 级(外部)split(),并且
  • , 为 2nd 一级(内部)。

然后我们应用这 2 个拆分。

注意:如果你有重要的理由获得tuples(而不是足够好的内部lists),只需应用tuple() 最后语句中的函数:

     result = [tuple(el.split(",")) for el in temp]