Soy terrible con las expresiones regulares. Estoy tratando de reemplazar esto:
public static function camelize($word) {
return preg_replace('/(^|_)([a-z])/e', 'strtoupper("\\2")', $word);
}
con preg_replace_callback con una función anónima. No entiendo qué está haciendo \\ 2. O para el caso exactamente cómo funciona preg_replace_callback.
¿Cuál sería el código correcto para lograr esto?
preg_replace_callback
. Y\\2
se convertirá$matches[2]
en dicha devolución de llamada. ¿O qué parte te confunde específicamente?create_function
, es solo otro envoltorio máseval
. Debe usar una función anónima adecuada, a menos que esté atascado en PHP 5.2 por alguna razón.Respuestas:
En una expresión regular, puede "capturar" partes de la cadena coincidente con
(brackets)
; en este caso, está capturando las partes(^|_)
y([a-z])
del partido. Estos están numerados comenzando en 1, por lo que tiene referencias inversas 1 y 2. Coincidir 0 es la cadena coincidente completa.El
/e
modificador toma una cadena de reemplazo y sustituye la barra invertida seguida de un número (p\1
. Ej. ) Con la referencia inversa adecuada, pero debido a que está dentro de una cadena, necesita escapar de la barra invertida, para obtener'\\1'
. Luego (efectivamente) se ejecutaeval
para ejecutar la cadena resultante como si fuera código PHP (razón por la cual está en desuso, porque es fácil de usareval
de una manera insegura).En su
preg_replace_callback
lugar, la función toma una función de devolución de llamada y le pasa una matriz que contiene las referencias anteriores coincidentes. Entonces, donde habría escrito'\\1'
, en su lugar accede al elemento 1 de ese parámetro, por ejemplo, si tiene una función anónima del formulariofunction($matches) { ... }
, la primera referencia inversa está$matches[1]
dentro de esa función.Entonces un
/e
argumento de'do_stuff(\\1) . "and" . do_stuff(\\2)'
podría convertirse en una devolución de llamada de
function($m) { return do_stuff($m[1]) . "and" . do_stuff($m[2]); }
O en tu caso
'strtoupper("\\2")'
podría convertirse
function($m) { return strtoupper($m[2]); }
Tenga en cuenta que
$m
y$matches
no son nombres mágicos, son solo el nombre de parámetro que di al declarar mis funciones de devolución de llamada. Además, no tiene que pasar una función anónima, podría ser el nombre de una función como una cadena, o algo de la formaarray($object, $method)
, como con cualquier devolución de llamada en PHP , por ejemplofunction 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');
Al igual que con cualquier función, no puede acceder a variables fuera de su devolución de llamada (desde el alcance circundante) de forma predeterminada. Cuando usa una función anónima, puede usar la
use
palabra clave para importar las variables a las que necesita acceder, como se explica en el manual de PHP . por ejemplo, si el viejo argumento era'do_stuff(\\1, $foo)'
entonces la nueva devolución de llamada podría verse así
function($m) use ($foo) { return do_stuff($m[1], $foo); }
Gotchas
preg_replace_callback
es lugar de la/e
modificador de la expresión regular, por lo que necesita para eliminar esa bandera de su argumento "patrón". Entonces un patrón como/blah(.*)blah/mei
se convertiría/blah(.*)blah/mi
./e
modificador usó una variante deaddslashes()
internamente en los argumentos, por lo que algunos reemplazos usaronstripslashes()
para eliminarlo; en la mayoría de los casos, probablemente desee eliminar la llamada astripslashes
de su nueva devolución de llamada.fuente
preg_replace shim con soporte eval
Esto es muy desaconsejable. Pero si no es un programador, o realmente prefiere un código terrible, puede usar una
preg_replace
función sustituta para mantener su/e
bandera funcionando temporalmente ./** * Can be used as a stopgap shim for preg_replace() calls with /e flag. * Is likely to fail for more complex string munging expressions. And * very obviously won't help with local-scope variable expressions. * * @license: CC-BY-*.*-comment-must-be-retained * @security: Provides `eval` support for replacement patterns. Which * poses troubles for user-supplied input when paired with overly * generic placeholders. This variant is only slightly stricter than * the C implementation, but still susceptible to varexpression, quote * breakouts and mundane exploits from unquoted capture placeholders. * @url: https://stackoverflow.com/q/15454220 */ function preg_replace_eval($pattern, $replacement, $subject, $limit=-1) { # strip /e flag $pattern = preg_replace('/(\W[a-df-z]*)e([a-df-z]*)$/i', '$1$2', $pattern); # warn about most blatant misuses at least if (preg_match('/\(\.[+*]/', $pattern)) { trigger_error("preg_replace_eval(): regex contains (.*) or (.+) placeholders, which easily causes security issues for unconstrained/user input in the replacement expression. Transform your code to use preg_replace_callback() with a sane replacement callback!"); } # run preg_replace with eval-callback return preg_replace_callback( $pattern, function ($matches) use ($replacement) { # substitute $1/$2/… with literals from $matches[] $repl = preg_replace_callback( '/(?<!\\\\)(?:[$]|\\\\)(\d+)/', function ($m) use ($matches) { if (!isset($matches[$m[1]])) { trigger_error("No capture group for '$m[0]' eval placeholder"); } return addcslashes($matches[$m[1]], '\"\'\`\$\\\0'); # additionally escapes '$' and backticks }, $replacement ); # run the replacement expression return eval("return $repl;"); }, $subject, $limit ); }
En esencia, sólo incluye esa función en su código base y editar
preg_replace
apreg_replace_eval
dondequiera que el/e
se usó la bandera.Pros y contras :
preg_replace_callback
.Generador de código de reemplazo
Ahora bien, esto es algo redundante. Pero podría ayudar a aquellos usuarios que todavía están abrumados con la reestructuración manual de su código a
preg_replace_callback
. Si bien esto lleva más tiempo, un generador de código tiene menos problemas para expandir la/e
cadena de reemplazo en una expresión. Es una conversión sin complicaciones, pero probablemente sea suficiente para los ejemplos más frecuentes.Para usar esta función, edite cualquier
preg_replace
llamada rotapreg_replace_eval_replacement
y ejecútela una vez . Esto imprimirá elpreg_replace_callback
bloque correspondiente que se utilizará en su lugar./** * Use once to generate a crude preg_replace_callback() substitution. Might often * require additional changes in the `return …;` expression. You'll also have to * refit the variable names for input/output obviously. * * >>> preg_replace_eval_replacement("/\w+/", 'strtopupper("$1")', $ignored); */ function preg_replace_eval_replacement($pattern, $replacement, $subjectvar="IGNORED") { $pattern = preg_replace('/(\W[a-df-z]*)e([a-df-z]*)$/i', '$1$2', $pattern); $replacement = preg_replace_callback('/[\'\"]?(?<!\\\\)(?:[$]|\\\\)(\d+)[\'\"]?/', function ($m) { return "\$m[{$m[1]}]"; }, $replacement); $ve = "var_export"; $bt = debug_backtrace(0, 1)[0]; print "<pre><code> #---------------------------------------------------- # replace preg_*() call in '$bt[file]' line $bt[line] with: #---------------------------------------------------- \$OUTPUT_VAR = preg_replace_callback( {$ve($pattern, TRUE)}, function (\$m) { return {$replacement}; }, \$YOUR_INPUT_VARIABLE_GOES_HERE ) #---------------------------------------------------- </code></pre>\n"; }
Tenga en cuenta que simplemente copiar y pegar no es programación. Tendrá que adaptar el código generado a sus nombres de variables de entrada / salida reales o al contexto de uso.
$OUTPUT =
asignación debería desaparecer si lapreg_replace
llamada anterior se utilizó en unif
.Y la expresión de reemplazo puede exigir más mejoras de legibilidad o reelaboración.
stripslashes()
menudo se vuelve redundante en expresiones literales.use
oglobal
para / dentro de la devolución de llamada."-$1-$2"
referencias de captura entre comillas desiguales terminarán rotas sintácticamente por la transformación simple en"-$m[1]-$m[2]
.La salida del código es simplemente un punto de partida. Y sí, esto hubiera sido más útil como herramienta en línea. Este enfoque de reescritura de código (editar, ejecutar, editar, editar) es algo poco práctico. Sin embargo, podría ser más accesible para aquellos que están acostumbrados a la codificación centrada en tareas (más pasos, más descubrimientos). Entonces, esta alternativa podría frenar algunas preguntas más duplicadas.
fuente
No deberías usar flag
e
(oeval
en general).También puede usar la biblioteca T-Regx
pattern('(^|_)([a-z])')->replace($word)->by()->group(2)->callback('strtoupper');
fuente