2009-08-25 7 views
2

Je suis en train de faire correspondre une chaîne comme ceci:expression régulière pour analyser des données délimitées par canalisations entre accolades doubles

{{name|arg1|arg2|...|argX}} 

avec une expression régulière

J'utilise preg_match avec

/{{(\w+)\|(\w+)(?:\|(.+))*}}/ 

mais je reçois quelque chose comme ça, chaque fois que j'utilise plus de deux arguments

Array 
(
    [0] => {{name|arg1|arg2|arg3|arg4}} 
    [1] => name 
    [2] => arg1 
    [3] => arg2|arg3|arg4 
) 

Les deux premiers éléments ne peuvent pas contenir d'espaces, le reste peut. Peut-être que je travaille trop longtemps sur ce sujet, mais je ne trouve pas l'erreur - toute aide serait grandement appréciée.

Merci Jan

Répondre

4

Ne pas utiliser des expressions régulières pour ce genre de tâches simples. Qu'est-ce que vous avez vraiment besoin est:

$inner = substr($string, 2, -2); 
$parts = explode('|', $inner); 

# And if you want to make sure the string has opening/closing braces: 
$length = strlen($string); 
assert($inner[0] === '{'); 
assert($inner[1] === '{'); 
assert($inner[$length - 1] === '}'); 
assert($inner[$length - 2] === '}'); 
+1

D'accord, je dois préciser alors:
Je suis en train de faire correspondre un nombre inconnu de ces expressions dans un modèle de page html. donc un substrat facile n'est pas une possibilité ...Je vais utiliser l'expression rationnelle pour trouver {{([^}] +)}} et continuer avec l'éclatement. Merci! – Jan

+0

C'est une réponse plutôt paresseuse et transforme une tâche simple en écriture d'un million de chèques si vous voulez vraiment être sûr. Et au lieu de supprimer les parenthèses par sous-chaîne, pourquoi ne pas faire un str_replace (array ('{', '}'), '', $ string); –

+0

Cette réponse a été écrite avant la clarification. Et l'utilisation de str_replace() ne vous permet pas de ** vérifier ** que les crochets sont dans la chaîne. – soulmerge

0

devrait fonctionner pour n'importe où de 1 à N arguments

<?php 

$pattern = "/^\{\{([a-z]+)(?:\}\}$|(?:\|([a-z]+))(?:\|([a-z ]+))*\}\}$)/i"; 

$tests = array(
    "{{name}}"       // should pass 
    , "{{name|argOne}}"     // should pass 
    , "{{name|argOne|arg Two}}"   // should pass 
    , "{{name|argOne|arg Two|arg Three}}" // should pass 
    , "{{na me}}"       // should fail 
    , "{{name|arg One}}"     // should fail 
    , "{{name|arg One|arg Two}}"   // should fail 
    , "{{name|argOne|arg Two|arg3}}"  // should fail 
); 

foreach ($tests as $test) 
{ 
    if (preg_match($pattern, $test, $matches)) 
    { 
    echo $test, ': Matched!<pre>', print_r($matches, 1), '</pre>'; 
    } else { 
    echo $test, ': Did not match =(<br>'; 
    } 
} 
3

Le problème est ici: \ | (. +)

expressions régulières, par par défaut, associez autant de caractères que possible. Depuis . est un caractère, d'autres instances de | sont heureusement assortis aussi, ce qui n'est pas ce que vous voulez.

Pour éviter cela, vous devez exclure | de l'expression, en disant "correspondre à tout sauf |", résultant en \ | ([^ \ |] +).

0

Bien sûr, vous obtiendrez quelque chose comme ceci :) Il n'y a aucun moyen dans l'expression régulière pour renvoyer le nombre dynamique de correspondances - dans votre cas les arguments. En regardant ce que vous voulez faire, vous devriez suivre l'expression régulière actuelle et simplement exploser les arguments supplémentaires par '|' et ajoutez-les à un tableau args.

0

En effet, cela est du manuel PCRE:

Lorsqu'un sous-masque est répété, la valeur capturée est la sous-chaîne qui correspondait à l'itération finale. Par exemple, après (tweedle [dume] {3} \ s *) + a correspondu "tweedledum tweedledee" la valeur de la sous-chaîne capturée est "tweedledee". Toutefois, s'il existe sous-masques de capture imbriqués, les valeurs capturées correspondantes peuvent avoir été définies dans les itérations précédentes. Pour par exemple, après/(a ​​| (b)) +/correspond à "aba" la valeur de la seconde sous-chaîne capturée est "b".

Questions connexes