我有以下内容
"aa_bb" : "foo"
"pp_Qq" : "bar"
"Xx_yY_zz" : "foobar"我想把左边的内容转换成camelCase
"aaBb" : "foo"
"ppQq" : "bar"
"xxYyZz" : "foobar"守则如下:
// selects the left part
$newString = preg_replace_callback("/\"(.*?)\"(.*?):/", function($matches) {
// selects the characters following underscores
$matches[1] = preg_replace_callback("/_(.?)/", function($matches) {
//removes the underscore and uppercases the character
return strtoupper($matches[1]);
}, $matches[1]);
// lowercases the first character before returning
return "\"".lcfirst($matches[1])."\" : ".$matches[2];
}, $string);这段代码可以简化吗?
注意:内容总是一个字符串。
发布于 2019-10-07 16:40:34
首先,既然您已经有了要改进的工作代码,那么下次考虑在代码评审中发布您的问题,而不是堆叠溢出。
让我们开始改进您最初的方法:
$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:最少使用正则表达式。
缺点:需要两个回调函数,但这次第二个回调函数是由array_reduce而不是由preg_replace_callback调用的。
$result = preg_replace_callback('~["_][^"_]*(?=[^"]*"\s*:)~', function ($m) {
return ucfirst(strtolower(ltrim($m[0], '_')));
}, $str);pro:模式相对简单,回调函数也保持简单。这看起来是个很好的妥协。
缺点:模式不是很紧凑(但应该足够用例)
模式描述:该模式查找a_或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没有一个好的答案,什么看起来简单或复杂,真正取决于读者。
发布于 2019-10-03 11:19:33
您可以将回调与\G锚点和捕获组结合使用。
(?:"\K([^_\r\n]+)|\G(?!^))(?=[^":\r\n]*")(?=[^:\r\n]*:)_?([a-zA-Z])([^"_\r\n]*)各部分
(?:非捕获群"\K([^_\r\n]+)匹配",捕获组1匹配1+乘以除_或换行符以外的任何字符|或\G(?!^)在上一场比赛中断言位置,而不是在开始时
)紧群(?=[^":\r\n]*")积极展望,断言"(?=[^:\r\n]*:)积极展望,断言:_?匹配可选([a-zA-Z])捕获组2匹配a([^"_\r\n]*)捕获组3匹配0+乘以除_或换行符以外的任何字符例如
$re = '/(?:"\K([^_\r\n]+)|\G(?!^))(?=[^":\r\n]*")(?=[^:\r\n]*:)_?([a-zA-Z])([^"_\r\n]*)/';
$str = '"aa_bb" : "foo"
"pp_Qq" : "bar"
"Xx_yY_zz" : "foobar"
"Xx_yYyyyyyYyY_zz_a" : "foobar"';
$result = preg_replace_callback($re, function($matches) {
return strtolower($matches[1]) . strtoupper($matches[2]) . strtolower($matches[3]);
}, $str);
echo $result;输出
"aaBb" : "foo"
"ppQq" : "bar"
"xxYyZz" : "foobar"
"xxYyyyyyyyyyZzA" : "foobar"https://stackoverflow.com/questions/58211084
复制相似问题