python正则表达式如何对括号进行成对匹配?

时间:2021-09-26 06:10:10

有时我们需要匹配像( 100 * ( 50 + 15 ) )这样的可嵌套的层次性结构,这时简单地使用\(.+\)则只会匹配到最左边的左括号和最右边的右括号之间的内容(这里我们讨论的是贪婪模式,懒惰模式也有下面的问题)。假如原来的字符串里的左括号和右括号出现的次数不相等,比如( 5 / ( 3 + 2 ) ) ),那我们的匹配结果里两者的个数也不会相等。有没有办法在这样的字符串里匹配到最长的,配对的括号之间的内容呢?                          ”


在.Net Framework的正则表达式中,提供了”平衡组/递归匹配“的处理方法(见《 正则表达式30分钟入门教程》)。

在python中,又有什么方法较好的实现这种匹配呢?

9 个解决方案

#1


这已经不是正则表达式了,是context free grammar。你可以自己写一个parser,或者用PLY之类的工具生成一个parser。

#2


建议读一下“Python正则表达式操作指南”http://www.cnblogs.com/babykick/archive/2011/03/30/1999428.html

#3


正则表达式没法完成,写个递归函数从最外面,到最里面,直到找不到'('为止。

#4



def matchlp(s):
   spos = [];
   rs = "";
   for i in range(0, len(s)):
      if(s[i] == '('):
         spos.append(i);
         continue;
      if(s[i] == ')' and spos):
         ts = s[spos[-1]: i+1];
         if(len(ts) > len(rs)):
            rs = ts;
         spos.pop();
   return rs;

s = " 5 / ( 3 + 2 ) ) ),";
rs = matchlp(s);
print(rs);

#5


to 1#:
太复杂了,我有心无力

to 2#:
读完就能够回答楼主位的问题了吗?

to 3#:
是个办法,4#给出了具体实现

to 4#:
贴个友坛上的回复,相互学习:

import re
pattern_0 = r'\([^()]*\)'      #depth 0 pattern
pat_left = r'\((?:[^()]|'    
pat_right = r')*\)'
def pattern_generate(pattern, depth=0):
    while(depth):
        pattern = pat_left + pattern + pat_right
        depth -= 1
    return pattern

def main():
    data = r'test(1+2*(2-1)-3*(5+2)+10+(()))'
    pat = pattern_generate(pattern_0, 2)
    print('Pattern:', pat)
    prog = re.compile(pat)
    result = prog.search(data)
    if result:
        print('Find: {}'.format(result.group(0)))
    else:
        print('Can\'t match')

if __name__ == '__main__':
    main()

#6


4L不是3L实现,3L只能找到最深嵌套,最深不代表最长
5L也有问题, data = r'test(10000+1)(2000000+2)'; 找到的是(10000)+1

#7


(10000+1)

#8


引用 6 楼 i_nbfa 的回复:
4L不是3L实现,3L只能找到最深嵌套,最深不代表最长
5L也有问题, data = r'test(10000+1)(2000000+2)'; 找到的是(10000)+1


你是对的。

这是一个很复杂的问题,通过编程实现灵活性又差了很多。现在再看看,似乎1#的才是终极方案啊。

#9


那讨论的最终结果呢。  怎么没人粘出来。。。

#1


这已经不是正则表达式了,是context free grammar。你可以自己写一个parser,或者用PLY之类的工具生成一个parser。

#2


建议读一下“Python正则表达式操作指南”http://www.cnblogs.com/babykick/archive/2011/03/30/1999428.html

#3


正则表达式没法完成,写个递归函数从最外面,到最里面,直到找不到'('为止。

#4



def matchlp(s):
   spos = [];
   rs = "";
   for i in range(0, len(s)):
      if(s[i] == '('):
         spos.append(i);
         continue;
      if(s[i] == ')' and spos):
         ts = s[spos[-1]: i+1];
         if(len(ts) > len(rs)):
            rs = ts;
         spos.pop();
   return rs;

s = " 5 / ( 3 + 2 ) ) ),";
rs = matchlp(s);
print(rs);

#5


to 1#:
太复杂了,我有心无力

to 2#:
读完就能够回答楼主位的问题了吗?

to 3#:
是个办法,4#给出了具体实现

to 4#:
贴个友坛上的回复,相互学习:

import re
pattern_0 = r'\([^()]*\)'      #depth 0 pattern
pat_left = r'\((?:[^()]|'    
pat_right = r')*\)'
def pattern_generate(pattern, depth=0):
    while(depth):
        pattern = pat_left + pattern + pat_right
        depth -= 1
    return pattern

def main():
    data = r'test(1+2*(2-1)-3*(5+2)+10+(()))'
    pat = pattern_generate(pattern_0, 2)
    print('Pattern:', pat)
    prog = re.compile(pat)
    result = prog.search(data)
    if result:
        print('Find: {}'.format(result.group(0)))
    else:
        print('Can\'t match')

if __name__ == '__main__':
    main()

#6


4L不是3L实现,3L只能找到最深嵌套,最深不代表最长
5L也有问题, data = r'test(10000+1)(2000000+2)'; 找到的是(10000)+1

#7


(10000+1)

#8


引用 6 楼 i_nbfa 的回复:
4L不是3L实现,3L只能找到最深嵌套,最深不代表最长
5L也有问题, data = r'test(10000+1)(2000000+2)'; 找到的是(10000)+1


你是对的。

这是一个很复杂的问题,通过编程实现灵活性又差了很多。现在再看看,似乎1#的才是终极方案啊。

#9


那讨论的最终结果呢。  怎么没人粘出来。。。