2012-04-14 31 views
1

Ich versuche, eine Python-Regex zu schreiben, die der Signatur von einfachen Python-Funktionen entspricht. Like:Python-Regex für Python-Funktionssignaturen

def _func1_(arg1, arg2): 

Ich habe diese regex:

"def ([^\W\d]+\w*)(\((*[^\W\d]+\w* *,? *)*\)):" 

Leider ist dies nicht wirklich gut. In der Argumentliste können Leerzeichen innerhalb von Variablennamen stehen, und ein unnötiges Komma kann in der und der Argumentliste in meiner Regex stehen. Kann mir jemand mit der richtigen Regex für diesen Fall helfen? Danke im Voraus!

+3

Reguläre Ausdrücke sind keine Parser. –

+1

Warum nicht [die AST gehen] (http://docs.python.org/dev/library/ast.html)? –

+0

Das abschließende Komma ist tatsächlich von Python erlaubt. – 9000

Antwort

1

In der Tat schrieb ich vor kurzem eine einfache Regex für Funktion Header-Kommentare (Um meine Hausaufgaben für eine CS-Klasse automatisch zu formatieren). Hier ist der Kern von ihm:

"def (\w+)\s*\((.*?)\):" 

Für die Parameter, würde ich mit re verzichten und stattdessen str.split(',') auf Capture-Gruppe 1 verwenden. Es ist nicht nötig, es komplizierter zu machen, als es sein muss.

+1

'def fn (a = (1, 2)):' ist eine gültige Definition. Es muss komplizierter sein. –

+0

@ IgnacioVazquez-Abrams: Welcher Teil? Der 're' Teil meiner Antwort funktioniert immer noch einwandfrei. Ich kann sehen, wie die Verwendung von 'split (", ")' auf 'a = (1,2)' jedoch brechen würde. –

+0

@Ignacio: Es tut mir leid, vergessen zu erwähnen, meine Aufgabe ist einfacher, vielleicht war ich nicht klar. Die Argumentliste kann nur einfache Variablennamen wie in meinem Beispiel enthalten. – WonderCsabo

0

Wenn Sie die Funktionsdefinitionen walk AST importieren oder inspect verwenden können.

Wenn Sie mehr Parsing neben Signaturen durchführen müssen, berücksichtigen Sie pyparsing oder funcparselib.

Wenn Sie noch Regexs verwenden müssen, ertragen Sie mit mir.

import re 

# Python identifiers start with a letter or _, 
#and continue with these or digits. 
IDENT = '[A-Za-z_][A-Za-z_0-9]*' 

# Commas between identifiers can have any amout of space on either side. 
COMMA = '\s*,\s*' 

# Parameter list can contain some positional parameters. 
# For simplicity we ignore now named parameters, *args, and **kwargs. 
# We catch the entire list. 
PARAM_LIST = '\((' + IDENT+'?' + '(?:' + COMMA+IDENT + ')*'+ ')?\)' 

# Definition starts with 'def', then identifier, some space, and param list. 
DEF = 'def\s+(' + IDENT + ')\s*' + PARAM_LIST 

ident_rx = re.compile(IDENT) 
def_rx = re.compile(DEF) 


def test(s): 
    match = def_rx.match(s) 
    if match: 
     name, paramlist = match.groups() 
     # extract individual params 
     params = [x.group() for x in ident_rx.finditer(paramlist or '')] 
     print s, name, params 
    else: 
     print s, 'does not match' 

test('def foo(a, b)') 
test('def foo()') 
test('def foo(a,b,c , d, e)') 
test('deff foo()') 
test('def foo(a, 2b)') 

Beachten Sie, dass der obige Code nicht Parameter mit Standardwerten verarbeiten kann, *args oder **kwargs oder dem Komma, geschweige denn Dinge wie def foo(a, (b, c)) legal in Python 2. All dies kann hinzugefügt werden, aber die Komplexität steigen wird.

Also, es sei denn, Ihr Fall ist ziemlich einfach (das Codebeispiel oben ist Borderline), siehe Parser Links oben.

Verwandte Themen