web-dev-qa-db-fra.com

Remplacez le modificateur preg_replace () e par preg_replace_callback

Je suis terrible avec des expressions régulières. J'essaie de remplacer ceci:

public static function camelize($Word) {
   return preg_replace('/(^|_)([a-z])/e', 'strtoupper("\\2")', $Word);
}

avec preg_replace_callback avec une fonction anonyme. Je ne comprends pas ce que fait le \\ 2. Ou d'ailleurs, comment fonctionne preg_replace_callback.

Quel serait le code correct pour y parvenir?

82
Casey

Dans une expression régulière, vous pouvez "capturer" des parties de la chaîne correspondante avec (brackets); dans ce cas, vous capturez les parties (^|_) et ([a-z]) du match. Celles-ci sont numérotées à partir de 1, vous avez donc les références arrières 1 et 2. La correspondance 0 correspond à la chaîne correspondante.

Le modificateur /e Prend une chaîne de remplacement et substitue une barre oblique inverse suivie d'un nombre (par exemple, \1) Par la référence arrière appropriée. Toutefois, comme vous êtes dans une chaîne, vous devez barre oblique inverse, vous obtenez donc '\\1'. Il exécute ensuite (effectivement) eval d'exécuter la chaîne résultante comme si elle était PHP (c'est pourquoi elle est obsolète, car elle est facile à utiliser eval d'une manière peu sûre).

La fonction preg_replace_callback Prend à la place une fonction de rappel et lui transmet un tableau contenant les références arrières correspondantes. Donc, là où vous auriez écrit '\\1', Vous accéderez plutôt à l'élément 1 de ce paramètre - par exemple. si vous avez une fonction anonyme de la forme function($matches) { ... }, la première référence arrière est $matches[1] à l'intérieur de cette fonction.

Donc, un argument /e De

'do_stuff(\\1) . "and" . do_stuff(\\2)'

pourrait devenir un rappel de

function($m) { return do_stuff($m[1]) . "and" . do_stuff($m[2]); }

Ou dans votre cas

'strtoupper("\\2")'

pourrait devenir

function($m) { return strtoupper($m[2]); }

Notez que $m Et $matches Ne sont pas des noms magiques, ils sont simplement le nom du paramètre que j'ai donné lors de la déclaration de mes fonctions de rappel. De plus, vous n'avez pas besoin de passer une fonction anonyme, cela pourrait être un nom de fonction sous forme de chaîne, ou quelque chose de la forme array($object, $method), comme avec tout rappel en PHP , par exemple.

function stuffy_callback($things) {
    return do_stuff($things[1]) . "and" . do_stuff($things[2]);
}
$foo = preg_replace_callback('/([a-z]+) and ([a-z]+)/', 'stuffy_callback', 'fish and chips');

Comme pour toute fonction, vous ne pouvez pas accéder par défaut aux variables en dehors de votre rappel (à partir de la portée environnante). Lorsque vous utilisez une fonction anonyme, vous pouvez utiliser le mot clé use pour importer les variables auxquelles vous devez accéder, comme indiqué dans le manuel PHP du manuel ., Par exemple. si le vieil argument était

'do_stuff(\\1, $foo)'

alors le nouveau rappel pourrait ressembler à

function($m) use ($foo) { return do_stuff($m[1], $foo); }

Gotchas

  • L'utilisation de preg_replace_callback Est au lieu de le modificateur /e De la regex. Vous devez donc supprimer cet indicateur de votre argument "motif". Ainsi, un motif comme /blah(.*)blah/mei deviendrait /blah(.*)blah/mi.
  • Le modificateur /e A utilisé une variante de addslashes() en interne sur les arguments, de sorte que certains remplacements ont utilisé stripslashes() pour le supprimer; dans la plupart des cas, vous souhaiterez probablement supprimer l'appel de stripslashes de votre nouveau rappel.
72
IMSoP

Vous ne devriez pas utiliser le drapeau e (ni eval en général).

Vous pouvez également utiliser bibliothèque T-Regx

pattern('(^|_)([a-z])')->replace($Word)->by()->group(2)->callback('strtoupper');
0
Danon