我正在一个项目中,我需要根据内联定义的模式和范围来生成字符串列表。
说我有以下字符串:
"NAME_{1:2}_{3:5}"
每个括号都定义了上限和下限。
生成的结果应该是:
["NAME_1_3", "NAME_1_4", "NAME_1_5", "NAME_2_3", "NAME_2_4", "NAME_2_5"]
理想情况下,它应该无缝处理以下情况:
使用的约定是任意的,因此,只要定义可以独立包含在字符串中,那么我很乐意使用替代方法,因为这使得使用某些lib进行解析更加容易。
答案 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个步骤进行操作:
假设您可以有任意数量的{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)]
from itertools import product def generate_combos(ranges): return product (*ranges) # unpack the list
这只会帮助我们将列表传递给product
,这将完成所有艰苦的工作。
在这里,我们需要一个函数来将其他两个集合在一起。首先,它解析字符串以获取范围和名称。然后,对于笛卡尔乘积的每个组合,将数字迭代添加到名称中,然后存储结果:
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']