python括号匹配问题_支持通配符的括号匹配问题源码+详细流程代码(python)

问题:

判断一个有左括号和右括号、以及其他ASCII字符组成的表达式是合法。 判断条件是左括号-右括号数目、次序配对,可多层嵌套。如果有*,则*可作为0个或者1个右括号,如果匹配则输出ok,不匹配则输出不匹配字符所在字符串中的具体位置

示例:

((((***********))(((**           不匹配字符位置:18 结果:NOK

((((***********))(((**))         结果:OK

(()())((()))(()***)                 结果:OK

(()*)                                  结果:OK

*(()*()()*(((*                      不匹配字符位置:12 结果:NOK

(((())))*()(*((**                  结果:OK

((()(())*                            不匹配字符位置:1 结果:NOK

((**)(*())))                        不匹配字符位置:12 结果:NOK

***(((()())**                       结果:OK

(*))                                  不匹配字符位置:4 结果:NOK

()(())*(*)(                          不匹配字符位置:11 结果:NOK

((((******))(((**                  不匹配字符位置:13 结果:NOK

分析:

在字符串中,如果有右括号,则优先匹配右括号,再考虑是否要进行通配符匹配。因此,可以先求出通配符*最少需要多少个才能满足字符串中所有的的左括号匹配,计算公式为:

if  左括号数量 <= 右括号数量://右括号大于等于左括号,不用通配符*替换

max_replace_num=0

else://右括号比左括号少,如果有*则需要用*进行替换右括号

max_replace_num=左括号数量-右括号数量

因括号匹配问题是优先最近原则,因此,可以将左括号入栈,如果遇到右括号,从栈中弹出一个与之匹配,如果遇到通配符*,如果max_replace_num==0则直接跳过,否则先入队列,优先让右括号先进行匹配,等到再碰到下一个左括号时先让队列中的通配符*优先匹配完栈中的左括号,再让左括号入栈。

具体流程图:

详细代码:

def append_list(i,ch):

ch_list = []

ch_list.append(i)

ch_list.append(ch)

return ch_list

def breaket_match(one_str):

'''

:param one_str: 需要匹配的字符串

:return: 返回-1则说明匹配,否则返回不匹配位置

'''

left_len = one_str.count('(') #左括号个数

left_list = [] # 临时存放左括号字符串列表

right_list=[] #保存*的队列

if left_len <= one_str.count(')'): #右括号大于等于左括号,不用*替换

max_replace_num=0

else: #右括号比左括号少,如果有*则需要用*进行替换右括号

max_replace_num=left_len-one_str.count(')') #替换个数为左括号减去右括号个数

for i in range(len(one_str)):

if one_str[i] == '(': #碰到第一个左括号,把标志位设置为false,说明从这里加上进行正式匹配

flag=False

if len(right_list)==0:

left_list.append(append_list(i=i,ch=one_str[i])) #当前左括号和左括号位置入栈

else: #*替换最大可替换个数

k=len(right_list)

tmp_replace = max_replace_num

for j in range(k):

if len(left_list)==0 or j >tmp_replace-1:

break

else:

left_list.pop()

max_replace_num -= 1

right_list.clear()

left_list.append(append_list(i=i, ch=one_str[i])) # 当前*和*位置入栈

elif one_str[i] == ')':#如果当前字符时右括号,出栈

if len(left_list) != 0: # 如果栈中有元素与之匹配,没有元素,说明不匹配,返回位置

left_list.pop()

else:

return i + 1 # 不匹配,返回位置信息

else: #如果当前字符是*

if max_replace_num==0: #判断*是否需要进行右括号匹配,为0说明不需要进行替换

pass

else: #*需要替换为右括号

if len(left_list)!=0 : #如果栈中有元素与之匹配,没有元素,说明不匹配,返回位置,并且替*换个数-1

right_list.append(append_list(i=i, ch=one_str[i])) # 左括号和左括号位置入栈

else: #如果左括号个数为0,但是下一个与之匹配的为*,则跳过

pass

k = len(right_list)

tmp_replace=max_replace_num

for i in range(k):

if len(left_list) == 0 or i > tmp_replace-1:

break

else:

left_list.pop()

max_replace_num -= 1

if (len(left_list)!=0): #如果左括号栈中元素不为空,不匹配,返回位置信息

return left_list.pop()[0]+1

else:

return -1 #匹配,返回-1

def read_file(file_path):

'''

读取文件

:param file_path:

:return: 返回list集合,里面包含文件每一行的字符

'''

lines = []

try:

file = open(file_path) #打开文件

line = file.readline() #读取文件第一行

while 1:

line = line.strip('\n') #去掉换行符\n

lines.append(line) #把文件的每一行append到lines里面

line = file.readline()

if not line:

file.close()

break

except :

print("打开文件失败,请确认文件名和路径是否正确!")

return lines

def main():

# print("请输入文本文件路径:")

#读取文件

# filepath=input() #读取控制台谁的文件路径

lines=read_file("test.txt")

length_lines=len(lines)

#breaket_match(str)输入参数str为需要匹配的字符串,如果匹配成功,则返回true,如果匹配不成功,则返回false

file=open("result.txt","w")

for i in range(length_lines): #对读取出来的文件每一行进行匹配

result=breaket_match(one_str=lines[i])

if result==-1:

file.write("行号:第"+str(i+1)+"行; "+"源字符串:"+lines[i]+"; "+"结果:"+"OK"+"\n")

print("行号:第"+str(i+1)+"行; "+"源字符串:"+lines[i]+"; "+"结果:"+"OK")

else:

file.write("行号:第" + str(i+1) + "行; " + "源字符串:" + lines[i] + "; " +"不匹配字符位置:"+str(result)+ " 结果:" + "NOK"+"\n")

print("行号:第" + str(i+1) + "行; " + "源字符串:" + lines[i] + "; " +"不匹配字符位置:"+str(result)+ " 结果:" + "NOK")

file.close()

if __name__ == '__main__':

main()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值