首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PHP - preg_replace_callback for camelCasing

PHP - preg_replace_callback for camelCasing
EN

Stack Overflow用户
提问于 2019-10-03 00:59:35
回答 2查看 178关注 0票数 1

我有以下内容

代码语言:javascript
复制
"aa_bb" : "foo"
"pp_Qq" : "bar"
"Xx_yY_zz" : "foobar"

我想把左边的内容转换成camelCase

代码语言:javascript
复制
"aaBb" : "foo"
"ppQq" : "bar"
"xxYyZz" : "foobar"

守则如下:

代码语言:javascript
复制
// 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);

这段代码可以简化吗?

注意:内容总是一个字符串。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-10-07 16:40:34

首先,既然您已经有了要改进的工作代码,那么下次考虑在代码评审中发布您的问题,而不是堆叠溢出。

让我们开始改进您最初的方法:

代码语言:javascript
复制
$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的模式方法:

代码语言:javascript
复制
$pattern = '~(?|\G(?!^)_([^_"]*)|("(?=[^"]*"\s*:)[^_"]*))~';
$result = preg_replace_callback($pattern, function ($m) {
    return ucfirst(strtolower($m[1]));
}, $str);

pro:代码更短,不需要使用两个preg_replace_callback

缺点:模式来自更复杂的地方。

注意:当您编写一个长模式时,没有什么可以禁止在x修饰符中使用空闲间距模式和放置注释:

代码语言:javascript
复制
$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';

这两个极端之间是否有妥协,好的是什么?有两项建议:

代码语言:javascript
复制
$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调用的。

代码语言:javascript
复制
$result = preg_replace_callback('~["_][^"_]*(?=[^"]*"\s*:)~', function ($m) {
    return ucfirst(strtolower(ltrim($m[0], '_')));
}, $str);

pro:模式相对简单,回调函数也保持简单。这看起来是个很好的妥协。

缺点:模式不是很紧凑(但应该足够用例)

模式描述:该模式查找a_或a“,并匹配以下不是_或a的字符。然后,一个前瞻性断言检查这些字符是否在关键部分中,寻找结束引号和冒号。匹配结果总是类似于_aBc"aBc (在回调函数中左侧裁剪下划线,而"在应用ucfirst后保持不变)。

模式细节:

代码语言:javascript
复制
["_] # 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

没有一个好的答案,什么看起来简单或复杂,真正取决于读者。

票数 1
EN

Stack Overflow用户

发布于 2019-10-03 11:19:33

您可以将回调\G锚点和捕获组结合使用。

代码语言:javascript
复制
(?:"\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+乘以除_或换行符以外的任何字符

在替换中,使用三个捕获组将斯特托洛弗绞线器结合在一起。

Regex演示

例如

代码语言:javascript
复制
$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;

输出

代码语言:javascript
复制
"aaBb" : "foo"

"ppQq" : "bar"

"xxYyZz" : "foobar"
"xxYyyyyyyyyyZzA" : "foobar"

Php演示

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58211084

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档