1

Je suis en train de développer un système de template et de rencontrer quelques problèmes.Preg_match_all avec des correspondances imbriquées

Le projet est de créer des documents HTML avec [@tags] dans ceux-ci. je pouvais utiliser str_replace (je rigole en boucle tous les remplacements posible), mais je veux pousser un peu plus loin ;-)

Je veux autoriser les balises imbriquées, et permettre à des paramètres de chaque tag:

[@title|You are looking at article [@articlenumber] [@articlename]] 

Je voudrais obtenir les résultats suivants avec preg_match_all:

[0] title|You are looking at article [@articlenumber] [@articlename] 
[1] articlenumber 
[2] articlename 

Mon script diviser le | pour les paramètres. La sortie de mon script sera quelque chose comme:

<div class='myTitle'>You are looking at article 001 MyProduct</div> 

Le problème que je vais avoir est que je ne suis pas exprerienced avec regex. Al mes paterns résultats presque ce que je veux, mais ont des problèmes avec les params imbriqués.

\[@(.*?)\] 

S'arrêtera à l'adresse] à partir de articlenumber.

\[@(.*?)(((?R)|.)*?)\] 

Est plus comme ça, mais il n'attrape pas l'articlenumber; https://regex101.com/r/UvH7zi/1

J'espère que quelqu'un pourra m'aider! Merci d'avance!

+0

Je crois qu'il est temps d'utiliser un analyseur html approprié, comme http://simplehtmldom.sourceforge.net/;) Voici un résumé sur les modèles récursifs pcre, mais cela va déraper très rapidement http: // www.rexegg.com/regex-recursion.html. –

Répondre

1

Vous ne pouvez pas utiliser les expressions régulières générales Python. Vous recherchez une fonctionnalité similaire à "balancing groups" disponible dans le. NET RegEx's engine qui permet des correspondances imbriquées.

Jetez un oeil à PyParsing qui permet l'expression imbriquée: de pyparsing importation nestedExpr

import pyparsing as pp 
text = '{They {mean to {win}} Wimbledon}' 
print(pp.nestedExpr(opener='{', closer='}').parseString(text)) 

La sortie est:

[['They', ['mean', 'to', ['win']], 'Wimbledon']] 

Malheureusement, cela ne fonctionne pas très bien avec votre exemple. Vous avez besoin d'une meilleure grammaire, je pense.

Vous pouvez tester une définition QuotedString, mais toujours.

import pyparsing as pp 
single_value = pp.QuotedString(quoteChar="'", endQuoteChar="'") 
parser = pp.nestedExpr(opener="[", closer="]", 
         content=single_value, 
         ignoreExpr=None) 

example = "['@title|You are looking at article' ['@articlenumber'] ['@articlename']]" 
print(parser.parseString(example, parseAll=True)) 
+0

La chose la plus proche de votre sortie désirée en utilisant votre modèle original que j'ai pu trouver était la suivante: '\ [@ (. *?) (\ B ((? R) |?) *?) * \]' – wp78de

+0

wp78de: this est le plus proche de ce que j'ai eu. Le problème est lors de l'imbrication d'une autre balise dans le titre, il n'est pas trouvé parce que le nombre de paramètres ne sont pas dynamiques. Mais votre réponse était extrêmement proche de ce dont j'avais besoin –

+0

Et je suis désolé de ne pas mentionner ma langue de programme, j'utilise PHP. Pour l'instant j'ai mis en cage un analyseur: '- obtenir tous les tags d'ouverture, et de mettre leurs strpos dans le tableau - creux début de boucle toutes les positions des balises d'ouverture - Recherchez le prochain closingtag, est-il avant la prochaine ouverture -marque? - Si le code de fermeture était après une étiquette d'ouverture, sautez celui-ci et cherchez le suivant (et continuez de vérifier les étiquettes entre les deux) ' De cette façon, je pourrais trouver toutes les étiquettes complètes et les remplacer. Mais cela a pris environ 50 lignes de code et plusieurs boucles, donc un preg_match serait plus grand ;-) –

0

Pour l'instant je suis un analyseur EMBALLÉES:

- get all opening tags, and put their strpos in array - loop trough all start positions of the opening tags - Look for the next closingtag, is it before the next open-tag? than the tag is complete - If the closingtag was after an opening tag, skip that one and look for the next (and keep checking for openingtags in between)

De cette façon, je pourrais trouver tous les tags complets et remplacez-les. Mais cela a pris environ 50 lignes de code et plusieurs boucles, donc un preg_match serait plus ;-)

1

je tape sur mon téléphone afin qu'il pourrait y avoir des erreurs, mais ce que vous voulez peut être assez facile à réaliser en incorporant un préanalyse dans votre expression:

(?=\\[(@(?:\\[(?1)\\]|.)*)\\]) 

Edit: Eh oui, cela fonctionne, ici vous allez: https://regex101.com/r/UvH7zi/4

Parce que (? =) consomme pas de caractères, le modèle cherche et capture le contenu de tous "[@ *]" sous-chaînes dans le sujet, en vérifiant récursivement que le contenu contient lui-même groupes, le cas échéant.