如何实现按括号层级拆分数学表达式的breakInChunks函数并修复输出异常
程序说明
需要实现breakInChunks()函数,该函数接收1个参数temp_s: string,temp_s为数学表达式,例如1+(3-e^(x-6))-8+(99-4)*10。函数需要识别左、右括号,将括号内的表达式替换为格式为[i$j]的块(i为左括号下标,j为右括号下标)。若某个完整块[m$n]内部包含多个子块,程序需要将m到n区间的字符整体替换为[m$n]。最终函数返回keypairs字典,键为块标识,值为从原始字符串中截取的对应内容,例如{'23$28': 'string within 23 and 28 characters'}。所有括号外的剩余字符也需要按相同的块:字符串格式追加到字典末尾。
输入输出示例
- 输入示例:
(7+x+8*(9+10(11+12)+14))-(2*(34)) - 输出示例:
{'12$18': '11+12', '7$22': '9+10[12$18]+14', '0$23': '7+x+8*[7$22]', '28$31': '34', '25$32': '2*[28$31]', '24:25': '-'}
问题描述
处理更复杂的字符串时返回结果异常,示例如下:
输入:
(7+y+(66+7)+(32+(78*19-(32-0)))+(32-9))+8+9+(9-10)-(9/7)-10
异常输出:
{'5$10': '66+7', '23$28': '32-0', '16$29': '78*19-[23$28', '12$30': '32+[16$29]))+8+9+', '32$37': '32-9', '0$38': '7+y+(66+7)+(32+[16$29][23$28]]37]])+8', '44$49': '9-10', '51$55': '9/7', '11:0': '', '31:0': '', '39:44': '+8+9+', '50:51': '-', }
具体表现:当一个块内部包含多个独立子块时,程序会将多个子块内容错误拼接,无法正确返回单个外层块。
现有代码
def findall(sstr, substr): gen = sstr.find(substr) while gen != -1: yield gen gen = sstr.find(substr, gen + 1) def findclosest(l: list, el: list): # find closest string from L to string from EL j = el[ 1 ] minimum = j min_index = 0 for i in range(len(l)): if l[ i ][ 0 ] - j < minimum: minimum = l[ i ][ 0 ] - j min_index = l[ i ][ 0 ] return min_index def breakInChunks(temp_s): # main list_of_additions = [ ] list_of_opened = list(findall(temp_s, '(')) list_of_closed = list(findall(temp_s, ')')) if sum(list_of_opened) < sum(list_of_closed) and len(list_of_opened) == len( list_of_closed): n = 0 # <WHILE> while len( list_of_closed) != 0: # read strings-expressions from the most inner ones to the most outer ones minimum = list_of_closed[ len(list_of_closed) - 1 ] j = list_of_closed.pop(0) for i in range(len(list_of_opened)): # find the closest opening bracket to the most inner closing one diff = j - list_of_opened[ i ] if diff > 0: if diff <= minimum: pop_index = i minimum = j - list_of_opened[ i ] else: break starting_index = list_of_opened.pop(pop_index) # start filling KEYPAIRS if len(keypairs) == 0: # if KEYPAIRS is empty keypairs[ f'{starting_index}${j}' ] = temp_s[ starting_index + 1:j ] else: # if KEYPAIRS has at least one key-value pair keys = [ key.split('$') for key in keypairs.keys() ] # reading and unpacking key-value pairs (reading indecies) innerSeq = temp_s min_index_i = None min_index_j = None prevExtracted_i = 0 prevExtracted_j = 0 for p in range(len(keys) - 1, -1, -1): k = keys[ p ] extracted_i, extracted_j = int(k[ 0 ]), int(k[ 1 ]) if starting_index < extracted_i: # if the chunk we are checking contains another one, we are checking if it's in fact the closest one to the chunk we are checking if ( extracted_i < prevExtracted_i and prevExtracted_j < extracted_j) or prevExtracted_i == 0: min_index_i = extracted_i min_index_j = extracted_j if prevExtracted_i == 0: if extracted_i > int(keys[ p - 1 ][ 0 ]) and extracted_j < int(keys[ p - 1 ][ 1 ]): pass else: innerSeq = innerSeq[ :extracted_i ] + f'[{extracted_i}${extracted_j}]' + innerSeq[ extracted_j + 1: ] else: if min_index_i is not None: innerSeq = innerSeq[ :min_index_i ] + f'[{min_index_i}${min_index_j}]' + innerSeq[ min_index_j + 1: ] min_index_i = None min_index_j = None else: innerSeq = innerSeq[ :prevExtracted_i ] + f'[{prevExtracted_i}${prevExtracted_j}]' + innerSeq[ prevExtracted_j + 1: ] prevExtracted_i = extracted_i prevExtracted_j = extracted_j n += 1 keypairs[ f'{starting_index}${j}' ] = innerSeq[ starting_index + 1:j ] # </WHILE> # checking if there are any strings outside parentheses left temp = [ [ int(key.split('$')[ 0 ]), int(key.split('$')[ 1 ]) ] for key in sorted(keypairs.keys(), key=lambda el: int( el.split('$')[1])) ] # sort from the most inner to the most outer for i in range(len(temp) - 1): if temp[ i ][ 1 ] < temp[ i + 1 ][ 0 ]: # if there is a gap between parentheses # find the closest difference in order to find actual string outside chunks with the help of findclosest() # add new chunk to LIST_OF_ADDITIONS list_of_additions.append([ temp[ i ][ 1 ] + 1, findclosest(temp[ i + 1: ], temp[ i ]) ]) if len(list_of_additions) > 0: # if something is inside LIST_OF_ADDITIONS # add remaining strings to KEYPAIRS for addition in list_of_additions: keypairs[ f'{addition[ 0 ]}:{addition[ 1 ]}' ] = self.s[ addition[ 0 ]:addition[ 1 ] ] return keypairs # return KEYPAIRS else: raise RuntimeError(f'Amount of closing and opening brackets does not match')
内容的提问来源于stack exchange,提问作者JoshJohnson
相关产品推荐
相关产品推荐

