Regex匹配相等数量的两个字符



我想使用正则表达式将任何函数的参数匹配为字符串。作为一个例子,我们假设以下字符串:

predicate(foo(x.bar, predicate(foo(...), bar)), bar)

这可能是较长序列的一部分

predicate(foo(x.bar, predicate(foo(...), bar)), bar)predicate(foo(x.bar, predicate(foo(...), bar)), bar)predicate(foo(x.bar, predicate(foo(...), bar)), bar)

我现在想找到表示函数/谓词及其参数的所有子字符串(即,在第一个示例中,整个字符串以及嵌套的predicate(foo(...), bar)(。问题是我不能像这个那样简单地匹配

predicate(.*, bar)

因为如果*是贪婪的,则i可以匹配多于谓词的参数,或者如果它是懒惰的,则匹配少于谓词的参数。这是因为这样的谓词((可以嵌套。

我需要一个正则表达式来查找字符串predicate(...),其中...与包含相等数量的()(惰性(的任何字符串匹配。

如果重要的话:我在python中使用带有re模块的regex。

按照@Tim Pietzcker的建议,添加PyPI包正则表达式,就可以使用递归正则表达式。

>>> import regex
>>> s = 'predicate(foo(x.bar, predicate(foo(...), bar)), bar)'
>>> pattern = regex.compile(r'(w+)(?=(((?:w+((?2))|[^()])*)))')
>>> pattern.findall(s)
[('predicate', 'foo(x.bar, predicate(foo(...), bar)), bar'),
 ('foo', 'x.bar, predicate(foo(...), bar)'),
 ('predicate', 'foo(...), bar'),
 ('foo', '...')]

您也可以限制它只查找"谓词":

>>> pattern = regex.compile(r'(predicate)(?=(((?:w+((?2))|[^()])*)))')
>>> pattern.findall(s)
[('predicate', 'foo(x.bar, predicate(foo(...), bar)), bar'),
 ('predicate', 'foo(...), bar')]
import re
def parse(s):
    pattern = re.compile(r'([^(),]+)|s*([(),])s*')
    stack = []
    state = 0 # 0 = before identifier, 1 = after identifier, 2 = after closing paren
    current = None
    args = []
    for match in pattern.finditer(s):
      if match.group(1):
        if state != 0:
          raise SyntaxError("Expected identifier at {0}".format(match.start()))
        current = match.group(1)
        state = 1
      elif match.group(2) == '(':
        if state != 1:
          raise SyntaxError("Unexpected open paren at {0}".format(match.start()))
        stack.append((args, current))
        state = 0
        current = None
        args = []
      elif match.group(2) == ',':
        if state != 0: args.append(current)
        state = 0
        current = None
      elif match.group(2) == ')':
        if state != 0: args.append(current)
        if len(stack) == 0:
          raise SyntaxError("Unmatched paren at {0}".format(match.start()))
        newargs = args
        args, current = stack.pop()
        current = (current, newargs)
        state = 2
    if state != 0: args.append(current)
    if len(stack) > 0: 
      raise SyntaxError("Unclosed paren")
    return args
>>> from pprint import pprint
>>> pprint(parse('predicate(foo(x.bar, predicate(foo(...), bar)), bar)'), width=1)
[('predicate',
  [('foo',
    ['x.bar',
     ('predicate',
      [('foo',
        ['...']),
       'bar'])]),
   'bar'])]

它返回所有以逗号分隔的顶级表达式的列表。函数调用变成名称和参数的元组。

您可以创建一个正则表达式来查找代码中的所有函数调用。类似这样的东西:

([_a-zA-Z]+)(?=()

然后使用re模块,创建一个数据结构,为代码中的函数调用建立索引。

import re
code = 'predicate(foo(x.bar, predicate(foo(...), bar)), bar)predicate(foo(x.bar, predicate(foo(...), bar)), bar)predicate(foo(x.bar, predicate(foo(...), bar)), bar)'
code_cp = code
regex = re.compile(r'([_a-zA-Z]+)(?=()')
matches = re.findall(regex, code)
structured_matches = []
for m in matches:
    beg = str.index(code, m)
    end = beg + len(m)
    structured_matches.append((m, beg, end))
    code = code[:beg] + '_' * len(m) + code[end:]

这将给你一个看起来像这样的数据结构:

[
  ('predicate', 0, 9),
  ('foo', 10, 13),
  ('predicate', 21, 30),
  ('foo', 31, 34),
  ('predicate', 52, 61),
  ('foo', 62, 65),
  ('predicate', 73, 82),
  ('foo', 83, 86),
  ('predicate', 104, 113),
  ('foo', 114, 117),
  ('predicate', 125, 134),
  ('foo', 135, 138)
]

您可以将此数据结构与parse函数结合使用,以提取每个函数调用的parens的内容。

def parse(string):
    stack = []
    contents = ''
    opened = False
    for c in string:
        if len(stack) > 0:
            contents += c
        if c == '(':
            opened = True
            stack.append('o')
        elif c == ')':
            stack.pop()
            if opened and len(stack) == 0:
                break
    return contents[:-1]

paren_contents = []
for m in structured_matches:
    fn_name, beg, end = m
    paren_contents.append((fn_name, parse(code_cp[end:])))

最后,paren_contents应该是这样的:

[
  ('predicate', 'foo(x.bar, predicate(foo(...), bar)), bar'),
  ('foo', 'x.bar, predicate(foo(...), bar)'),
  ('predicate', 'foo(...), bar'), ('foo', '...'),
  ('predicate', 'foo(x.bar, predicate(foo(...), bar)), bar'),
  ('foo', 'x.bar, predicate(foo(...), bar)'),
  ('predicate', 'foo(...), bar'), ('foo', '...'),
  ('predicate', 'foo(x.bar, predicate(foo(...), bar)), bar'),
  ('foo', 'x.bar, predicate(foo(...), bar)'),
  ('predicate', 'foo(...), bar'),
  ('foo', '...')
]

希望这能为你指明正确的方向。

相关内容

  • 没有找到相关文章

最新更新