Sou péssimo com expressões regulares. Estou tentando substituir isso:
public static function camelize($word) {
return preg_replace('/(^|_)([a-z])/e', 'strtoupper("\\2")', $word);
}
com preg_replace_callback com uma função anônima. Não entendo o que o \\ 2 está fazendo. Ou exatamente como funciona preg_replace_callback.
Qual seria o código correto para conseguir isso?
preg_replace_callback
. E\\2
se tornará$matches[2]
no dito retorno de chamada. Ou sobre qual parte você está confuso especificamente?create_function
, é apenas mais um invólucroeval
. Você deve usar uma função anônima adequada, a menos que esteja preso no PHP 5.2 por algum motivo.Respostas:
Em uma expressão regular, você pode "capturar" partes da string combinada com
(brackets)
; neste caso, você está capturando as partes(^|_)
e([a-z])
da partida. Eles são numerados começando em 1, então você tem referências anteriores 1 e 2. Match 0 é toda a string combinada.O
/e
modificador pega uma string de substituição e substitui a barra invertida seguida por um número (por exemplo\1
) com a referência inversa apropriada - mas porque você está dentro de uma string, você precisa escapar da barra invertida, então você consegue'\\1'
. Em seguida, ele (efetivamente) executaeval
para executar a string resultante como se fosse um código PHP (por isso está sendo descontinuado, porque é fácil de usareval
de uma maneira insegura).A
preg_replace_callback
função, em vez disso, recebe uma função de retorno de chamada e passa a ela uma matriz contendo as referências anteriores correspondentes. Então, onde você teria escrito'\\1'
, você acessa o elemento 1 desse parâmetro - por exemplo, se você tem uma função anônima do formuláriofunction($matches) { ... }
, a primeira referência anterior está$matches[1]
dentro dessa função.Então, um
/e
argumento de'do_stuff(\\1) . "and" . do_stuff(\\2)'
pode se tornar um retorno de chamada de
function($m) { return do_stuff($m[1]) . "and" . do_stuff($m[2]); }
Ou no seu caso
'strtoupper("\\2")'
poderia se tornar
function($m) { return strtoupper($m[2]); }
Observe que
$m
e$matches
não são nomes mágicos, eles são apenas o nome do parâmetro que dei ao declarar minhas funções de retorno de chamada. Além disso, você não precisa passar uma função anônima, pode ser um nome de função como uma string, ou algo na formaarray($object, $method)
, como em qualquer retorno de chamada em PHP , por exemplofunction 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');
Como com qualquer função, você não pode acessar variáveis fora de seu retorno de chamada (do escopo circundante) por padrão. Ao usar uma função anônima, você pode usar a
use
palavra-chave para importar as variáveis que você precisa acessar, conforme discutido no manual do PHP . por exemplo, se o antigo argumento era'do_stuff(\\1, $foo)'
então o novo retorno de chamada pode parecer
function($m) use ($foo) { return do_stuff($m[1], $foo); }
Pegadinhas
preg_replace_callback
é , em vez do/e
modificador na regex, então você precisa para remover a bandeira de seu argumento "padrão". Portanto, um padrão como/blah(.*)blah/mei
se tornaria/blah(.*)blah/mi
./e
modificador usou uma variante deaddslashes()
internamente nos argumentos, portanto, algumas substituições foram usadasstripslashes()
para removê-lo; na maioria dos casos, você provavelmente deseja remover a chamada parastripslashes
de seu novo retorno de chamada.fonte
preg_replace shim com eval support
Isso é muito desaconselhável. Mas se você não for um programador, ou realmente preferir um código terrível, você pode usar uma
preg_replace
função substituta para manter seu/e
sinalizador funcionando temporariamente ./** * 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 ); }
Em essência, você acabou de incluir essa função em sua base de código, e edita
preg_replace
parapreg_replace_eval
onde quer que o/e
foi usado bandeira.Prós e contras :
preg_replace_callback
.Gerador de código de substituição
Agora, isso é um tanto redundante. Mas pode ajudar os usuários que ainda estão sobrecarregados com a reestruturação manual de seu código para
preg_replace_callback
. Embora isso consuma efetivamente mais tempo, um gerador de código tem menos problemas para expandir a/e
string de substituição em uma expressão. É uma conversão nada notável, mas provavelmente é suficiente para os exemplos mais comuns.Para usar esta função, edite qualquer
preg_replace
chamada interrompida empreg_replace_eval_replacement
e execute-a uma vez . Isso imprimirá opreg_replace_callback
bloco correspondente a ser usado em seu 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"; }
Lembre-se de que apenas copiar e colar não é programação. Você terá que adaptar o código gerado de volta aos nomes reais das variáveis de entrada / saída ou ao contexto de uso.
$OUTPUT =
atribuição teria que ser encerrada se apreg_replace
chamada anterior fosse usada em umif
.E a expressão de substituição pode exigir mais melhorias de legibilidade ou retrabalho.
stripslashes()
muitas vezes se torna redundante em expressões literais.use
ouglobal
para / dentro do retorno de chamada."-$1-$2"
referências de captura entre aspas desigualmente terminarão quebradas sintaticamente pela transformação simples em"-$m[1]-$m[2]
.A saída do código é apenas um ponto de partida. E sim, isso teria sido mais útil como uma ferramenta online. Essa abordagem de reescrita de código (editar, executar, editar, editar) é um pouco impraticável. No entanto, poderia ser mais acessível para aqueles que estão acostumados com a codificação centrada em tarefas (mais etapas, mais descobertas). Portanto, essa alternativa pode conter mais algumas perguntas duplicadas.
fonte
Você não deve usar flag
e
(oueval
em geral).Você também pode usar a biblioteca T-Regx
pattern('(^|_)([a-z])')->replace($word)->by()->group(2)->callback('strtoupper');
fonte