2009-03-29 5 views
13

J'essaie de faire correspondre une chaîne qui peut apparaître sur plusieurs lignes. Il commence et se termine par une chaîne spécifique:Ajout de nouvelles lignes dans la fonction PHP preg_replace

{a}some string 
can be multiple lines 
{/a} 

Puis-je saisir tout entre {a} et {/a} avec une expression régulière? Il semble que le. ne correspond pas aux nouvelles lignes, mais j'ai essayé ce qui suit sans succès:

$template = preg_replace($'/\{a\}([.\n]+)\{\/a\}/', 'X', $template, -1, $count); 
echo $count; // prints 0 

Il correspond. ou \ n quand ils sont seuls, mais pas ensemble!

Répondre

31

Utilisez le s modifier:

$template = preg_replace($'/\{a\}([.\n]+)\{\/a\}/s', 'X', $template, -1, $count); 
//            ^
echo $count; 
+0

Génial, je savais que ce serait quelque chose de simple comme ça! – DisgruntledGoat

+0

En outre, je viens de trouver que cette information est sur le site PHP, même si je ne l'ai jamais trouvé avant de regarder ... http://www.php.net/manual/fr/reference.pcre.pattern.modifiers .php – DisgruntledGoat

3

De http://www.regular-expressions.info/dot.html:

"Le point correspond à un seul caractère, sans se soucier de ce que le caractère est La seule exception sont newline caractères."

Vous devrez ajouter un indicateur de fin/s à votre expression.

6

Je pense que vous avez plus de problèmes que le point qui ne correspond pas aux nouvelles lignes, mais laissez-moi commencer par une recommandation de formatage. Vous pouvez utiliser n'importe quel caractère de ponctuation comme délimiteur de regex, pas seulement la barre oblique ('/'). Si vous utilisez un autre personnage, vous n'aurez pas à échapper des barres obliques dans l'expression régulière. Je comprends que '%' est populaire parmi les PHPers; qui rendrait votre argument pattern:

'%\{a\}([.\n]+)\{/a\}%' 

Maintenant, la raison pour laquelle regex ne fonctionne pas comme vous aviez l'intention est que le point perd sa signification spéciale quand il apparaît dans une classe de caractères (les crochets) - si [.\n] correspond juste à un point ou à un saut de ligne. Ce que vous recherchez était (?:.|\n), mais j'aurais recommandé correspondant au retour chariot ainsi que le saut de ligne:

'%\{a\}((?:.|[\r\n])+)\{/a\}%' 

C'est parce que le mot « saut de ligne » peut se référer au style Unix « \ n », Windows "\ r \ n", ou plus ancien style "\ r". Toute page Web donnée peut contenir l'un de ceux-ci ou un mélange de deux styles ou plus; un mélange de "\ n" et "\ r \ n" est très commun. Mais avec/s mode (également connu sous le nom unique en ligne ou en mode DOTALL), vous ne devez pas vous inquiéter à ce sujet:

'%\{a\}(.+)\{/a\}%s' 

Cependant, il y a un autre problème avec le regex d'origine qui est toujours présent dans celui-ci: le + est gourmand. Cela signifie que s'il y a plus d'une séquence {a}...{/a} dans le texte, la première fois que votre regex est appliquée, elle correspondra à toutes les séquences, du premier {a} au dernier {/a}. La façon la plus simple de résoudre ce problème est de rendre le + ungreedy (alias, « paresseux » ou « réticent ») en ajoutant un point d'interrogation:

'%\{a\}(.+?)\{/a\}%s' 

Enfin, je ne sais pas quoi faire de la « $ 'avant la citation d'ouverture de votre argument de motif. Je ne fais pas PHP, mais cela ressemble à une erreur de syntaxe. Si quelqu'un pouvait m'éduquer à ce sujet, je l'apprécierais.

+0

Oh, ça doit être une faute de frappe - j'utilisais à l'origine une variable et je l'ai remplacée par une chaîne pour cet exemple. – DisgruntledGoat

+0

C'était une excellente explication. Bravo pour ça. – craignewkirk

Questions connexes