Regex che combina tag iniziali e finali nidificati

Qui ci sono le stringhe che mi piacerebbe estrarre il contenuto tra i tag {{if}} e {{\if}} , intendo il primo e l'ultimo (quelli interni saranno ricontrollati dal motore):

  • "prima di {{if ^^ p1 ^ p2}} IN1; {{if ^ ^ p1}} {{iif}} IN3 {{/ if}} IN1-1 {{/ if}} dopo"
  • "prima di {{if ^ ^ p1}} IN1; {{if ^ ^ p1}} {{if ^ ^ p1}} IN3 {{/ if}} {{/ if}} IN1-1 {{/ if}} dopo"
  • "prima di {{if ^ ^ p1}} IN1; {{if ^ ^ p1}} {{if ^ ^ p1}} IN3 {{/ if}} {{/ if}} IN1-1 {{if ^ ^ p1 }} IN4 {{/ if}} {{/ if}} dopo "

La regex è: \{\{(if)\}\}(((?!\{\{\/?\1\}\})[\s\S])*(\{\{\1\}\}(?2)*\{\{\/\1\}\})*((?!\{\{\/?\1\}\})[\s\S])*)\{\{\/\1\}\}

MODIFICA 3: ho rimosso l'obbligo di supportre i TAG senza terminarne uno. Ho riformattato la domanda per gli utenti futur, per capire alcuni commenti qui sotto, vedere la prima versione del post

Inoltre, ce l'ho per funzionare tutti e tre allo stesso tempo, dandomi tre match, che non funziona sul sito web regex101. Le interruzioni di row devono essere supportte all'interno della partita. Però, potrei accettare che solo le ultime due combinate iif due match perché potrei cambiare il tag di solo if per iif .

La mia altra soluzione non sta usando le espressioni regolari, ma mi piacerebbe farlo se è ansible.

Puoi usare

 ~{{ # Opening tag start (\w+) # (Group 1) Tag name \^ # Aux delimiter ([^^\{\}]?) # (Group 2) Specific delimiter \^ # Aux delimiter ([^\{\}]+) # (Group 3) Parameters }} # Opening tag end ( # (Group 4) (?> (?R) # Repeat the whole pattern | # or match all that is not the opening/closing tag [^{]*(?:\{(?!{/?\1[^\{\}]*}})[^{]*)* )* # Zero or more times ) {{/\1}} # Closing tag ~ix 

Guarda la demo regex

In generale, l'espressione si basa sulla ricorsione e un token goloso temperato . [^{]*(?:\{(?!{/?\1[^\{\}]*}})[^{]*)* è un srotolato (?s:(?!{{/?\1}}).)* model che corrisponde a qualsiasi carattere ( . ) Che non è il punto di partenza per una sequenza di caratteri {{TAG}} o {{/TAG}} .

Non hai bisogno di un modificatore DOTALL per questo model in quanto non c'è . nel model.

Ecco una demo PHP :

 $re = '~{{(\w+)\^([^^\{\}]?)\^([^\{\}]+)}}((?>(?R)|[^{]*(?:\{(?!{/?\1[^\{\}]*}})[^{]*)*)*){{/\1}}~i'; $str = "before {{if^^p1^p2}} IN1; {{if^ ^p1}} {{iif}} IN3 {{/if}} IN1-1 {{/if}} after\nbefore {{if^ ^p1}} IN1; {{if^ ^p1}} {{if^ ^p1}} IN3 {{/if}} {{/if}} IN1-1 {{/if}} after\nbefore {{if^ ^p1}} IN1; {{if^ ^p1}} {{if^ ^p1}} IN3 {{/if}} {{/if}} IN1-1 {{if^ ^p1}} IN4 {{/if}} {{/if}} after"; preg_match_all($re, $str, $matches); print_r($matches);