Я ужасен с регулярными выражениями. Я пытаюсь заменить это:
public static function camelize($word) {
return preg_replace('/(^|_)([a-z])/e', 'strtoupper("\\2")', $word);
}
с preg_replace_callback с анонимной функцией. Я не понимаю, что делает \\ 2. Или, если на то пошло, как именно работает preg_replace_callback.
Какой правильный код для этого?
preg_replace_callback
. И\\2
станет$matches[2]
в обратном вызове. Или в какой части конкретно вы запутались?create_function
, это просто еще одна оберткаeval
. Вам следует использовать подходящую анонимную функцию, если вы по какой-то причине не застряли в PHP 5.2.Ответы:
В регулярном выражении вы можете «захватывать» части совпадающей строки с помощью
(brackets)
; в этом случае вы захватываете(^|_)
и([a-z])
части матча. Они нумеруются, начиная с 1, поэтому у вас есть обратные ссылки 1 и 2. Соответствие 0 - это вся совпадающая строка./e
Модификатор принимает строку замены, и заменяет бэкслеш числа (например\1
) с соответствующей обратной ссылкой - но потому , что вы находитесь внутри строки, вам нужно , чтобы избежать обратной косых черт, так что вы получите'\\1'
. Затем он (эффективно) запускаетeval
результирующую строку, как если бы это был код PHP (поэтому он устарел, потому что его легко использоватьeval
небезопасным способом).preg_replace_callback
Функции , а не принимает функцию обратного вызова и передает его массив , содержащий совпавшие обратные ссылки. Таким образом, там, где вы бы написали'\\1'
, вместо этого вы получаете доступ к элементу 1 этого параметра - например, если у вас есть анонимная функция формыfunction($matches) { ... }
, первая обратная ссылка находится$matches[1]
внутри этой функции.Итак,
/e
аргумент'do_stuff(\\1) . "and" . do_stuff(\\2)'
может стать обратным вызовом
function($m) { return do_stuff($m[1]) . "and" . do_stuff($m[2]); }
Или в вашем случае
'strtoupper("\\2")'
мог стать
function($m) { return strtoupper($m[2]); }
Обратите внимание, что
$m
и$matches
не являются волшебными именами, это просто имя параметра, которое я дал при объявлении моих функций обратного вызова. Кроме того, вам не нужно передавать анонимную функцию, это может быть имя функции в виде строки или что-то в формеarray($object, $method)
, как с любым обратным вызовом в PHP , например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');
Как и в случае с любой функцией, по умолчанию вы не можете получить доступ к переменным вне вашего обратного вызова (из окружающей области). При использовании анонимной функции вы можете использовать
use
ключевое слово для импорта переменных, к которым вам нужно получить доступ, как описано в руководстве по PHP. . например, если старый аргумент был'do_stuff(\\1, $foo)'
тогда новый обратный вызов может выглядеть как
function($m) use ($foo) { return do_stuff($m[1], $foo); }
Попался
preg_replace_callback
является вместо с/e
модификатором на регулярном выражении, так что вам нужно удалить этот флаг из вашего «шаблона» аргумента. Так шаблон вроде/blah(.*)blah/mei
бы стал/blah(.*)blah/mi
./e
Модификатор используется вариантaddslashes()
внутренне на аргументы, так что некоторые замены используютсяstripslashes()
для его удаления; в большинстве случаев вы, вероятно, захотите удалить вызовstripslashes
из нового обратного вызова.источник
preg_replace shim с поддержкой eval
Это очень нецелесообразно. Но если вы не программист или действительно предпочитаете ужасный код, вы можете использовать заменяющую
preg_replace
функцию, чтобы ваш/e
флаг временно работал ./** * 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 ); }
В сущности, вы просто включить эту функцию в вашем коде, и редактировать
preg_replace
вpreg_replace_eval
там , где/e
был использован флаг.Плюсы и минусы :
preg_replace_callback
.Генератор кода замены
Теперь это несколько избыточно. Но может помочь тем пользователям, которым все еще сложно вручную реструктурировать свой код в формат
preg_replace_callback
. Хотя это фактически требует больше времени, у генератора кода меньше проблем с/e
преобразованием строки замены в выражение. Это ничем не примечательное преобразование, но его, вероятно, достаточно для наиболее распространенных примеров.Чтобы использовать эту функцию, отредактируйте любой прерванный
preg_replace
вызовpreg_replace_eval_replacement
и запустите его один раз . Это распечатает соответствующийpreg_replace_callback
блок, который будет использоваться вместо него./** * 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"; }
Помните, что простое копирование и вставка - это не программирование. Вам придется адаптировать сгенерированный код обратно к вашим фактическим именам переменных ввода / вывода или контексту использования.
$OUTPUT =
присвоение должно быть выполнено, если предыдущийpreg_replace
вызов использовался вif
.И выражение замены может потребовать дополнительных улучшений читабельности или переделки.
stripslashes()
буквальные выражения часто становятся избыточными.use
илиglobal
ссылка для / в обратном вызове."-$1-$2"
захвата, заключенные неравномерно в кавычки, будут синтаксически нарушены простым преобразованием в"-$m[1]-$m[2]
.Вывод кода - это просто отправная точка. И да, это было бы более полезно в качестве онлайн-инструмента. Такой подход к переписыванию кода (редактирование, запуск, редактирование, редактирование) в некоторой степени непрактичен. Тем не менее, он может быть более доступным для тех, кто привык к программированию, ориентированному на задачи (больше шагов, больше открытий). Таким образом, эта альтернатива может ограничить еще несколько повторяющихся вопросов.
источник
Вы не должны использовать флаг
e
(илиeval
вообще).Вы также можете использовать библиотеку T-Regx
pattern('(^|_)([a-z])')->replace($word)->by()->group(2)->callback('strtoupper');
источник