在许多正文中都有括号,特别是在表示程序、数学表达式的正文片段里,括号有正确配对问题。作为例子,下面考虑python程序里的括号,在这里可以看到:
- 存在多种不同的括号,下面只考虑其中三种:圆括号、方括号和花括号。
- 每种括号都包括一个开括号和一个闭括号,相互对应。括号括起的片段可能嵌套,各种括号应该正确地嵌套并分别配对。
不难总结出检查括号配对的原则:在扫描正文过程中,遇到的闭括号应该与此前最近遇到且尚未获得匹配的开括号配对。如果最近的未匹配开括号与当前闭括号不配对,或者找不到这样的开括号,就是匹配失败,说明这段正文里的括号不配对。
由于存在多种不同的括号对,每种括号都可能出现任意多次,而且还可能嵌套。为了检查是否匹配,扫描中必须保存遇到的开括号。由于写程序时无法预知要处理的正文里会有多少括号需要保存,因此不能用固定数目的变量保存,必须用缓存结构。
由于括号的出现可能嵌套,需要逐对匹配:当前闭括号应该与前面最近的尚未配对的开括号匹配,下一个闭括号应与前面次近的括号匹配。这说明,需要存储的开括号的使用原则是后存人者先使用,符合LIFO原则。
进而,如果一个开括号已配对,就应该删除这个括号,为随后的匹配做好准备。显然,在扫描中,后遇到并保存的开括号将先配对并被删除,这就是按出现的顺序后进先出。这些情况说明,用栈保存遇到的开括号可以正确支持匹配工作。
通过上面分析,处理这个问题的脉络已经很清楚了:
- 顺序扫描被检查正文(一个字符串)里的一个个字符。
- 检查中跳过无关字符(所有非括号字符都与当前处理无关)。
- 遇到开括号时将其压人栈。
- 遇到闭括号时弹出当时的栈顶元素与之匹配。
- 如果匹配成功则继续,发现不匹配时检查以失败结束。
def check_parens(text):
"""括号配对检查函数,text是被检查的正文串"""
parens="()[]{}" #要检查配对的所有括号
open_parens="([{" #开括号
opposite={")":"(","]":"[","}":"{"} #表示配对关系的字典
def parentheses(text):
"""括号生成器,每次调用返回text里的下一括号及其位置"""
i,text_len=0,len(text)
while True:
while i<text_len and text[i] not in parens:
i+=1
if i>=text_len:
return
yield text[i],i
i+=1
st=SStack() #栈
for p,i in parentheses(text):
if p in open_parens:
st.push(p)
else:
if opposite[p]!=st.pop():
print("\n匹配失败")
return False
print("\n匹配成功")
return True