2016-09-26 33 views
1

正規表現を使用して任意の関数のパラメータを文字列として照合したいと思います。例は次の文字列とさせて頂きますよう:正規表現一致する2文字の文字数

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\) 

のように一致して傾けることです。そのような述語()はネストすることができるからです。

私は...(年代と)年代(遅延)の等量を含む任意の文字列にマッチする文字列predicate(...)が見つかった正規表現を必要とします。

重要:私はreモジュールをpythonで使用しています。

+0

[この回答](http://stackoverflow.com/a/24696831/2272638)は右につながるかもしれません方向?まだ十分なコーヒーは、私が答えを投稿したいと思っています。 – dwanderson

+0

Pythonの 're'モジュールはここで必要とする再帰やバランスを扱うことができません。 ['regex'モジュール(PyPI)](https://pypi.python.org/pypi/regex)をインストールできますか? –

+0

@dwanderson悲しいことに、(または私はIDを取得しません)それは同等の量のparanthesesに一致しようとすると、それはちょうど(とa) – weidler

答えて

1

PyPI package regexを追加すると、@ Tim Pietzckerが示唆したように、recursive regexesを使用できます。

>>> 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')] 
+0

ありがとう!再帰は(?2)のグループをそれ自身で呼び出すほど簡単ですか? – weidler

+0

はい。グループに繰り返したいことがすべて含まれていることを確認するだけです。詳細については、http://www.regular-expressions.info/recurse.htmlを参照してください。 –

1
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'])] 

それはすべてカンマで区切られたトップレベルの式のリストを返します。関数呼び出しは、名前と引数のタプルになります。

+0

これはすでに私が思った方法ですが、あまりにも多くのコードを使用することは避けてください。これは正規表現で解決することができると期待しています。特にパフォーマンスが向上する可能性があります。 – weidler

1

正規表現を作成して、コード内のすべての関数呼び出しを見つけることができます。このような何か:

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

その後reモジュールを使用して、あなたのコード内の関数呼び出しをインデックスのデータ構造を作成します。

[ 
    ('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機能と連動して、このデータ構造を使用することができます。

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', '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', '...') 
] 

がうまくいけば、これが正しい方向にあなたを指す:最後に

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は次のようになります。

+0

Markus Jarderotsと同じ回答です。私がすでに教えた方法ですが、特にこれがパフォーマンスを向上させる可能性があるので、正規表現で解決することが可能でしょう – weidler

関連する問題