2009-07-08 6 views

Répondre

5

Il y a certaines choses que les expressions régulières ne sont pas très bonnes. Cela ne signifie pas qu'il est impossible de construire une expression qui fonctionne, mais que ce n'est probablement pas un bon choix. Parmi ces choses:

  • entrée multi-ligne
  • nidification

blocs fonctionnels Javascript ont tendance à couvrir plusieurs lignes, et vous allez vouloir trouver le correspondant « { » et « } » accolades qui signifient le début et la fin du bloc, qui pourrait être imbriqué à une profondeur inconnue. Vous devez également tenir compte des accolades potentielles utilisées dans les commentaires. RegEx sera douloureux pour cela. Cela ne veut pas dire que c'est impossible, cependant. Vous pourriez avoir des informations supplémentaires sur la nature des fonctions que vous recherchez. Si vous pouvez faire des choses comme ne pas garantir d'accolades dans les commentaires et limiter l'imbrication à une profondeur spécifique, vous pouvez toujours créer une expression pour le faire. Ce sera quelque peu désordonné et difficile à maintenir, mais au moins dans le domaine du possible.

+2

En quoi la saisie sur plusieurs lignes est-elle un problème? – Zifre

+0

Cela dépend du moteur, certains ne le supportent pas. d'autres ont des bugs. –

+1

N'est-ce pas plus un problème des moteurs que des regex? – Zifre

3

Non, il est impossible. Les expressions régulières ne peuvent pas correspondre à des paires de caractères imbriquées. Donc, quelque chose comme cela le tromper:

function foo() { 
    if(bar) { 
     baz(); 
    } // oops, regex would think this was end of function 
} 

Cependant, vous pouvez créer une grammaire assez simple de le faire (sous forme EBNF-ish):

 
javascript_func 
: "function" ID "(" ")" "{" body* "}" 
| "function" ID "(" params ")" "{" body* "}" 
; 

params 
: ID 
| params "," ID 

body 
: [^{}]* // assume this is like a regex 
| "{" body* "}" 
; 

Oh, cela est aussi en supposant que vous avez une sorte de lexer pour enlever les espaces et les commentaires.

+0

@Zifre Je ne renonce pas, mais j'espère que cela est correct! – leeand00

+1

En fait, une regex gourmande correspondrait à toute la fonction. Cependant, si une autre fonction le suivait, elle serait également saisie. – GalacticCowboy

+0

Oh, et vous pouvez avoir des fonctions imbriquées aussi ... (définition de fonction dans un autre) – GalacticCowboy

5

Pas vraiment, non.

Les blocs fonctionnels ne sont pas réguliers et les expressions régulières ne sont pas le bon outil pour le travail. Voir, afin de capturer un bloc de fonction dans JS, vous devez compter les instances de { et les équilibrer par rapport aux instances de }, sinon vous allez faire correspondre trop ou trop peu. Les expressions régulières ne peuvent pas faire ce genre de comptage.

Lisez simplement le fichier que vous essayez de visualiser et gérez récursivement l'imbrication. C'est conceptuellement très facile à gérer de cette façon.

2

Certains moteurs d'expressions rationnelles autorisent la récursivité. Dites en PHP ou PCRE vous pourriez obtenir parenthèses imbriquées comme ceci:?

{(?:[^{}]+|(?R))*+} 

R « pâtes » l'expression entière à sa place. Pour capturer des fonctions sous-groupes seront plus utiles:

function[^{]+({(?:[^{}]+|(?-1))*+}) 

Et puis nous pourrions filtrer les commentaires briser les supports (besoins sm drapeaux):

function\s+\w+\s*\([^{]+({(?:[^{}]+\/\*.*?\*\/|[^{}]+\/\/.*?$|[^{}]+|(?-1))*+}) 

Cela devrait fonctionner pour les cas de base. Mais il y a encore des chaînes avec '}', des chaînes avec des guillemets échappés et d'autres choses à s'inquiéter.

Voici une démo: https://regex101.com/r/fG4gO1/2

+0

vraiment cool. je fais quelques changements. 'function ([^ {] +) ({(?: [^ {}] + \/\ *. *? \ * \/| [^ {}] + \/\ /.*? $ | [^ { }] + | (? - 1)) * +}) ' – Eugene

5

J'ai une solution javascript très efficace, contrairement à la croyance tout le monde elses ... essayer, je l'ai utilisé et il fonctionne très bien function\s*([A-z0-9]+)?\s*\((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*\)\s*\{(?:[^}{]+|\{(?:[^}{]+|\{[^}{]*\})*\})*\}

https://regex101.com/r/zV2fO7/1

2

Après une journée de bidouillage pour mon propre projet, voici une regex qui va décomposer un fichier js pour correspondre à toutes les fonctions nommées, puis le décomposer en nom de fonction, arguments et corps.

function\s+(?<functionName>\w+)\s*\((?<functionArguments>(?:[^()]+)*)?\s*\)\s*(?<functionBody>{(?:[^{}]+|(?-1))*+}) 

https://regex101.com/r/sXrHLI/1

+0

Très bien! J'ai essayé une classe ES6, et elle a trouvé les fonctions embarquées (mais pas les méthodes bien sûr). Cela a même fonctionné pour le code minifié. Je vois que les parens supplémentaires dans les commentaires sont un problème. Je peux personnellement choisir d'éviter l'analyse syntaxique pour les fonctions. – AAron

Questions connexes