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

问题:

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

源码下载地址:http://download.csdn.net/download/u011128775/10167555#comment

示例:

((((***********))(((**           不匹配字符位置: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()

源码+visio流程图+测试用例下载地址:http://download.csdn.net/download/u011128775/10167555#comment

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
通配符匹配问题可以使用动态规划来解决。具体的实现如下: ```python def is_match(s, p): m, n = len(s), len(p) # 创建一个二维数组 dp,用于记录匹配状态 dp = [[False] * (n+1) for _ in range(m+1)] dp[0][0] = True # 处理模式串 p 以连续的 '*' 开头的情况 for j in range(1, n+1): if p[j-1] == '*': dp[0][j] = dp[0][j-1] # 动态规划遍历字符串 s 和模式串 p for i in range(1, m+1): for j in range(1, n+1): if p[j-1] == '?' or s[i-1] == p[j-1]: dp[i][j] = dp[i-1][j-1] elif p[j-1] == '*': dp[i][j] = dp[i][j-1] or dp[i-1][j] return dp[m][n] ``` 这里使用一个二维数组 `dp` 来记录匹配状态。`dp[i][j]` 表示字符串 `s` 的前 `i` 个字符和模式串 `p` 的前 `j` 个字符是否匹配。初始时,将 `dp[0][0]` 设置为 `True`,表示两个空串是匹配的。然后处理模式串 `p` 以连续的 '*' 开头的情况,如果遇到 '*',则将 `dp[0][j]` 设置为 `dp[0][j-1]`。 接下来,使用动态规划遍历字符串 `s` 和模式串 `p`。如果当前字符匹配或者模式串中为 '?' 通配符,则将当前匹配状态设为上一个匹配状态 `dp[i-1][j-1]`。如果当前字符为 '*' 通配符,则可以选择忽略该字符(`dp[i][j-1]`)或者将该字符匹配多个前面的字符(`dp[i-1][j]`)。最终返回 `dp[m][n]`,其中 `m` 和 `n` 分别为字符串 `s` 和模式串 `p` 的长度。 你可以调用 `is_match` 函数并传入两个字符串来测试它的功能。例如: ```python s = "acdcb" p = "a*c?b" result = is_match(s, p) print(result) # 输出:True ``` 这里的字符串 `s` 匹配模式串 `p`,返回结果为 `True`。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值