Во-первых, поскольку у вас уже есть рабочий код, который вы хотите улучшить, рассмотрите возможность размещения вашего вопроса в обзоре кода вместо stackoverflow в следующий раз.
Давайте начнем улучшать ваш оригинальный подход:
$result = preg_replace_callback('~"[^"]*"\s*:~', function ($m) {
return preg_replace_callback('~_+(.?)~', function ($n) {
return strtoupper($n[1]);
}, strtolower($m[0]));
}, $str);
pro: шаблоны относительно просты, и идея проста для понимания.
минусов: вложенных preg_replace_callback
могут повредитьглаза.
После этого упражнения для разогрева глаз мы можем попробовать \G
подход на основе шаблона:
$pattern = '~(?|\G(?!^)_([^_"]*)|("(?=[^"]*"\s*:)[^_"]*))~';
$result = preg_replace_callback($pattern, function ($m) {
return ucfirst(strtolower($m[1]));
}, $str);
pro: кодкороче, не нужно использовать два preg_replace_callback
.
минусов: шаблон гораздо более сложный.
примечание: когда вы пишете длинный шаблон,ничто не запрещает использовать свободный интервал с модификатором x и оставлять комментарии:
$pattern = '~
(?| # branch reset group: in which capture groups have the same number
\G # contigous to the last successful match
(?!^) # but not at the start of the string
_
( [^_"]* ) # capture group 1
|
( # capture group 1
"
(?=[^"]*"\s*:) # lookahead to check if it is the "key part"
[^_"]*
)
)
~x';
Есть ли компромиссы между этими двумя крайностями, и что является хорошим? Два предложения:
$result = preg_replace_callback('~"[^"]+"\s*:~', function ($m) {
return array_reduce(explode('_', strtolower($m[0])), function ($c, $i) {
return $c . ucfirst($i);
});
}, $str);
pro: минимальное использование регулярных выражений.
cons: нужны две функции обратного вызова, за исключением того, что на этот раз вторая вызываетсяarray_reduce
и не preg_replace_callback
.
$result = preg_replace_callback('~["_][^"_]*(?=[^"]*"\s*:)~', function ($m) {
return ucfirst(strtolower(ltrim($m[0], '_')));
}, $str);
pro: шаблон относительно прост, и функция обратного вызова также остается простой. Это выглядит как хороший компромисс.
минусы: шаблон не очень сужен (но должен подойти для вашего случая использования)
описание шаблона: шаблон ищет_ или a "и соответствует следующим символам, которые не являются _ или a". Затем предварительное утверждение проверяет, что эти символы находятся внутри ключевой части в поисках закрывающей кавычки и двоеточия. Результат совпадения всегда выглядит как _aBc
или "aBc
(подчеркивания обрезаются слева в функции обратного вызова и "
остается неизменным после применения ucfirst
).
детали шаблона:
["_] # one " or _
[^"_]* # zero or more characters that aren't " or _
(?= # open a lookahead assertion (followed with)
[^"]* # all that isn't a "
" # a literal "
\s* # eventual whitespaces
: # a literal :
) # close the lookahead assertion
Нет хорошего ответа, и то, что выглядит простым или сложным, действительно зависит от читателя.