在Python中生成一系列字符串模式的列表

时间:2019-03-17 21:11:32

标签: python string

我正在一个项目中,我需要根据内联定义的模式和范围来生成字符串列表。

说我有以下字符串:

"NAME_{1:2}_{3:5}"

每个括号都定义了上限和下限。

生成的结果应该是:

["NAME_1_3", "NAME_1_4", "NAME_1_5", "NAME_2_3", "NAME_2_4", "NAME_2_5"]

理想情况下,它应该无缝处理以下情况:

  1. “ NAME” => [“ NAME”]
  2. “ NAME_ {1:2}” => [“ NAME_1”,“ NAME_2”]

使用的约定是任意的,因此,只要定义可以独立包含在字符串中,那么我很乐意使用替代方法,因为这使得使用某些lib进行解析更加容易。

3 个答案:

答案 0 :(得分:0)

我认为解决此问题的最优雅,最动态的方法是使用递归:

import re

a = "NAME_{1:2}_{3:5}"
b = "NAME_{1:2}"
c = "NAME"
d = "NAME_{1:2}_{3:4}_{7:8}"

def recure(myRanges, myString, varReference):

    if not myRanges:
        varReference.append(myString)
        return

    for i in myRanges[0]:
        tempVar = myRanges[:]
        del tempVar[0]
        recure(tempVar, myString + "_" + str(i), varReference)


def getMyList(myInput):
    myInputList = list(myInput)

    a = [i.start() for i in re.finditer('{', myInput)]

    try:
        myName = myInput[:a[0] - 1]
    except:
        myName = myInput

    myRanges = [range(int(myInputList[i + 1]), int(myInputList[i + 3]) + 1) for i in a]

    myList = []

    recure(myRanges, myName, myList)

    return myList

print(getMyList(a)) # -> ['NAME_1_3', 'NAME_1_4', 'NAME_1_5', 'NAME_2_3', 'NAME_2_4', 'NAME_2_5']
print(getMyList(b)) # -> ['NAME_1', 'NAME_2']
print(getMyList(c)) # -> ['NAME']
print(getMyList(d)) # -> ['NAME_1_3_7', 'NAME_1_3_8', 'NAME_1_4_7', 'NAME_1_4_8', 'NAME_2_3_7', 'NAME_2_3_8', 'NAME_2_4_7', 'NAME_2_4_8']

原始帖子

可以做到以下事情

a = "NAME_{1:2}_{3:5}"
aList = list(a)

myString = a[:a.find("_")]

startI = int(aList[a.find("{") + 1])
endI = int(aList[a.find("}") - 1]) + 1

startII = int(aList[a.rfind("{") + 1])
endII = int(aList[a.rfind("}") - 1]) + 1

myList = []

for i in range(startI, endI):
    for j in range(startII, endII):
        myList.append(myString + "_" + str(i) + "_" + str(j))

print(myList) # -> ['NAME_1_3', 'NAME_1_4', 'NAME_1_5', 'NAME_2_3', 'NAME_2_4', 'NAME_2_5']

答案 1 :(得分:0)

另一种(更紧凑)的方式:

name, first, second = a.split('_')
first_range = range(int(first[1]), int(first[3]) + 1)
second_range = range(int(second[1]), int(second[3]) + 1)

res = ['{}_{}_{}'.format(name, i, j) for j in second_range for i in first_range]
# ['NAME_1_3', 'NAME_2_3', 'NAME_1_4', 'NAME_2_4', 'NAME_1_5', 'NAME_2_5']

答案 2 :(得分:0)

您要寻找的是Cartesian product。它实质上给出了两个列表输入的所有可能组合。值得庆幸的是,Python的itertools库具有内置的product类,可以用作迭代器。现在,我们要分3个步骤进行操作:

  1. 解析字符串
  2. 生成笛卡尔积
  3. 重建字符串

1。解析字符串

假设您可以有任意数量的{x:y},我们将使用while循环

def parse_string(string): 
    index_of_ = string.find ("_")
    name = string [:index_of_]
    if index_of_ == -1: return name, []
    ranges = []
    while index_of_ != -1:  # still an _
        next_underscore = string.find ("_", index_of_ + 1)
        if next_underscore == -1:  # last underscore
            range_ = string [index_of_ + 1:]
        else: range_ = string [index_of_ + 1:next_underscore]
        start = range_ [1 : range_.find (":")]
        end = range_ [range_.find (":") + 1 : -1]
        ranges.append (tuple (range (int (start), int (end) + 1)))  # put all those numbers in
        if next_underscore == -1: break
        else: index_of_ = next_underscore
    return name, ranges

此函数遍历字符串,提取名称,并迭代找到范围。它返回名称和所有范围的列表,因此对于您的示例-NAME,[(1,2),(3,4,5)]

2。生成组合

现在,我们有了所有范围的列表,让我们获取该列表的笛卡尔积。

from itertools import product   
    def generate_combos(ranges): 
        return product (*ranges)  # unpack the list

这只会帮助我们将列表传递给product,这将完成所有艰苦的工作。

3。生成字符串

在这里,我们需要一个函数来将其他两个集合在一起。首先,它解析字符串以获取范围和名称。然后,对于笛卡尔乘积的每个组合,将数字迭代添加到名称中,然后存储结果:

def generate_string(string): 
    name, ranges = parse_string (string)
    results = []
    for combo in generate_combos (ranges):
        result = name
        for num in combo: 
            result += f"_{num}"
        results.append (result)
    return results

一个例子:

print (generate_string ("NAME_{1:2}_{3:5}"))

赠予:

['NAME_1_3', 'NAME_1_4', 'NAME_1_5', 'NAME_2_3', 'NAME_2_4', 'NAME_2_5']