2010-10-14 44 views
1
script suivant

Envisagez (c'est un non-sens total pseudo-langue):script texte Divisé en sous-chaînes par modèle

if (Request.hostMatch("asfasfasf.com") && someString.existsIn(new String[] {"brr", "hrr"})) { 
    if (Requqest.clientIp("10.0.x.x")) { 
     somevar = "1"; 
    } 
    somevar = "2"; 
} 
else { 
    somevar = "first"; 
} 
string foo = "foo"; 
// etc. etc. 

Comment voulez-vous saisir si-bloc de paramètres et contenu de ce? Le cas du bloc a le format de:

if<whitespace>(<parameters>)<whitespace>{<contents>}<anything> 

J'ai essayé d'utiliser String.split() avec motif regex de ^if\s*\(|\)\s*\{|\}\s* mais échoue lamentablement. A savoir, le problème est que ) { se trouve également dans le bloc interne if et la fermeture } est trouvée à partir de nombreux endroits. Je ne pense pas que ni l'expansion paresseuse ou impatiente fonctionne ici.

Alors ... des pointeurs sur ce dont j'ai besoin ici pour l'implémenter avec regex?

J'ai également besoin d'obtenir la chaîne restante sans le code if-block (donc le code à partir de else { ...). L'utilisation de String.split() semble difficile car il n'y a aucune information sur la longueur des parties analysées.

J'ai initialement créé une solution basée sur une boucle (en utilisant String.substring() fortement) pour cela, mais c'est terne. Je voudrais avoir quelque chose d'amateur à la place. Dois-je aller avec regex ou créer une fonction générique, personnalisée (il y a beaucoup d'autres cas que cela) qui prend la chaîne parseable et le modèle à la place (pensez au modèle if<whitespace>(... ci-dessus)?

Édition: Les valeurs modifiées ont été renvoyées aux affectations de variables, car cela n'aurait pas été logique autrement.

+3

En tant que langage non-régulier, cela ne peut pas être analysé par regex. Vous devrez utiliser un analyseur si vous voulez que cela soit fait de manière fiable. – NullUserException

+0

Vous voulez élaborer ce que vous voulez dire par langage non régulier? La langue a une structure stricte, c'est très bash mais il y a des cas spéciaux, oui.Cependant, tout est "structuré". –

+0

Ok, les trucs non réguliers sont expliqués/liés dans la réponse de Trey. Regarde ça. –

Répondre

1

Une langue normale ne fonctionnera pas car un regular grammar ne peut pas correspondre à des choses comme «un nombre quelconque de parenthèses ouvrantes suivi d'un nombre quelconque de parenthèses fermantes». Un context-free grammar serait nécessaire pour cela.

Sauf si vous utilisez un context-free grammar parser for Java ou une extension d'expression régulière makes regular expressions no longer regular, votre solution basée sur une boucle est probablement la solution la plus élégante.

+0

Wow, ça a été bien plus technique que je ne l'étais. J'ai clairement des choses à étudier ici. Quoi qu'il en soit, je suppose que c'est la résolution alors, merci pour l'explication et les liens! –

+0

Pour plus d'informations sur ce champ, consultez le langage formel et la théorie des automates. –

2

Vous feriez mieux d'utiliser (ou d'écrire) un analyseur que d'essayer de le faire avec Regex. Regex est génial pour quelque chose, mais pour l'analyse complexe comme ça, ça craint. Un autre exemple où il est difficile de se faire beaucoup demander ici est l'analyse du code HTML - vous pouvez le faire dans une certaine mesure, mais pour quelque chose de complexe, un analyseur DOM est une bien meilleure solution.

Pour un analyseur simple [très], ce que vous avez besoin est une fonction récursive qui recherche un accolades { et }, récursion bas niveau chaque fois qu'il rencontre une accolade d'ouverture et de revenir en arrière un niveau quand il trouve une accolade de fermeture. Il doit ensuite stocker le contenu de la chaîne entre les deux accolades à chaque niveau.

+0

C'est agréable d'entendre des opinions et des suggestions aussi honnêtes. Ma mise en œuvre actuelle n'utilise pas la récursivité mais je suis d'accord que ce serait une meilleure solution. Merci pour votre contribution, malheureusement je choisis la réponse de Trey comme acceptée, désolé :) –

1

Comme ci-dessus, vous aurez besoin d'un analyseur. Un type facile à mettre en œuvre (et amusant à écrire!) Est un recursive descent parser with backtracking. Il y a aussi une pléthore de générateurs de parseurs, bien que la plupart d'entre eux aient une courbe d'apprentissage. Un générateur d'analyseur Java-friendly est JavaCC.

+0

Merci pour les pointeurs. La documentation de JavaCC semble beaucoup plus complète comparée à celle de Beaver. Cependant, les deux ont une courbe d'apprentissage comme vous le dites, donc je vais probablement avec une implémentation personnalisée. En lisant les analyseurs, je découvre que mon implémentation actuelle est assez similaire :) –

+0

Je n'ai jamais utilisé un générateur d'analyseur. Dans les rares occasions où j'en avais besoin, c'était assez simple pour coder à la main. –