Une expression régulière récalcitrante
Bonjour,
je cherche à faire un petit parseur de code C qui retrouve les prototypes des fonctions.
Je me suis fait le code suivant :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| def findall ( exp,str ):
'''Renvoie une liste de dict de toutes les occurrences de exp dans la chaîne str
(re.findall ne fait pas ce que je veux)'''
res,pos = [],0
while True :
match = exp.search( str[pos:],re.DOTALL )
if not match : return res
pos += match.end()-1
res += [ match.groupdict() ]
def find_all_proto ( source ):
'''Renvoie tous les prototypes C de source'''
regx = r'''(\W|\A)
(?P<type> (\w+ ( \* | \s+ )+ )+ )
(?P<name> \w+ )
\s*\(
(?P<param> .*? )
\) \s* ;'''
ex_proto = re.compile( regx,re.DOTALL+re.VERBOSE)
return findall( ex_proto,source )
def test_find_proto ():
s = '''void f1 ();
void f2 ( void ) ;
void f3( int x );void f4 ( int x , char * s );
void*f5 ( int x , char * s );
void* f6 ( int x , char * s );
void *f7 ( int x , char * s );
void * f8 ( int x , char * s );
int ** f9 ( int x , char * s );
int * * f10 ( int x , char * s );
int * ** f11 ( int x , char * s );
const int * ** f12 ( int x , char * s );
const int*const **f13 ( int x , char * s );
const int f14 ( int x , char * s );
static const int f15 ( int x , char * s );
'''
for p in find_all_proto( s ):
print '%-20s : %3s : %s'%(p.get('type'),p.get('name'),p.get('param',''))
test_find_proto() |
et j'obtiens ça :
Code:
1 2 3 4 5 6 7 8 9
| void : f2 : void
void : f4 : int x , char * s
void* : f6 : int x , char * s
void * : f8 : int x , char * s
int * * : f10 : int x , char * s
const int * ** : f12 : int x , char * s
int*const ** : f13 : int x , char * s
int : f14 : int x , char * s
const int : f15 : int x , char * s |
Comme vous pouvez le voir il me manque presque une fonction sur 2, à part les 13 et 15 dont il manque le premier mot.
Si je supprime la fin de l'expression régulière
Code:
1 2 3 4
| regx = r'''(\W|\A)
(?P<type> (\w+ ( \* | \s+ )+ )+ )
(?P<name> \w+ )
\s*\(''' |
j'obtiens ça :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13
| void : f2 :
void : f3 :
void* : f5 :
void* : f6 :
void * : f7 :
void * : f8 :
int ** : f9 :
int * * : f10 :
int * ** : f11 :
const int * ** : f12 :
const int*const ** : f13 :
const int : f14 :
static const int : f15 : |
Cette fois, j'ai bien toutes les fonctions et il ne manque aucun mot.
A part "f1" et "f4" qui manquent encore.
Donc, à vous les experts des reg exp : comment expliquer un tel comportement ?
Encore plus étrange :
Si j'ajoute une première ligne à mes prototypes de test, le résultat dépend du nombre de caractères :
Code:
1 2 3 4
| def test_find_proto ():
s = '''zzzzz
void f1 ();
.... |
j'ai bien "f1" mais je perds "f2" :
Code:
1 2 3 4 5 6 7
| void : f1 :
void : f3 :
void* : f5 :
void* : f6 :
void * : f7 :
void * : f8 :
... |
Mais avec un 'z' de moins, je pers à nouveau "f1".
Si quelqu'un a une idée... moi je suis à sec !
:arf:
Merci !