将数组键从underscore_case递归转换为camelCase

时间:2015-07-07 16:52:05

标签: php arrays regex recursion

我必须想出一种方法,使用不受欢迎的(underscore_case)将数组键转换为camelCase。这必须以递归方式完成,因为我不知道将向该方法提供什么数组。

我想出了这个:

private function convertKeysToCamelCase($apiResponseArray)
{
    $arr = [];
    foreach ($apiResponseArray as $key => $value) {
        if (preg_match('/_/', $key)) {
            preg_match('/[^_]*/', $key, $m);
            preg_match('/(_)([a-zA-Z]*)/', $key, $v);
            $key = $m[0] . ucfirst($v[2]);
        }


        if (is_array($value))
            $value = $this->convertKeysToCamelCase($value);

        $arr[$key] = $value;
    }
    return $arr;
}

它完成了这项工作,但我认为它可以做得更好,更简洁。多次调用preg_match然后连接看起来很奇怪。

你看到了整理这种方法的方法吗? 更重要的是,是否可以通过一次调用preg_match来执行相同的操作?这看起来怎么样?

6 个答案:

答案 0 :(得分:8)

递归部分不能进一步简化或美化。

但是,来自underscore_case(也称为snake_case)和camelCase的转换可以通过几种不同的方式完成:

$key = 'snake_case_key';
// split into words, uppercase their first letter, join them, 
// lowercase the very first letter of the name
$key = lcfirst(implode('', array_map('ucfirst', explode('_', $key))));

$key = 'snake_case_key';
// replace underscores with spaces, uppercase first letter of all words,
// join them, lowercase the very first letter of the name
$key = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $key))));

$key = 'snake_case_key':
// match underscores and the first letter after each of them,
// replace the matched string with the uppercase version of the letter
$key = preg_replace_callback(
    '/_([^_])/',
    function (array $m) {
        return ucfirst($m[1]);
    },
    $key
);

选择你最喜欢的!

答案 1 :(得分:3)

我可以快速发现两个单独的任务。一种是将字符串转换为camel-case格式,另一种是映射多维数组的键。这些任务与另一个任务无关,因此最好将它们作为单独的函数实现。

让我们从更高阶函数mapArrayKeys开始。它将接受映射函数并将此函数应用于数组的每个键,从而生成一个新数组。我们必须期望映射函数是单射的(一对一)。

function mapArrayKeys(callable $f, array $xs) {
  $out = array();
  foreach ($xs as $key => $value) {
    $out[$f($key)] = is_array($value) ? mapArrayKeys($f, $value) : $value;
  }
  return $out;
}

有一些我认为不那么重要的小点。您可能不想对参数进行类型提示,好吧。也许你宁愿if / then / else而不是三元运算符,好吧。重要的是,使用mapArrayKeys,您可以将任何(单射)映射函数应用于数组键。

第二项任务是将字符串转换为camel-case。您可以使用PCRE功能,这很好。我将使用explode进行拆分。

function underToCamel($str) {
  return lcfirst(implode('', array_map('ucfirst', explode('_', $str))));
}

现在这两个函数可以串联使用,以实现将数组键从下划线转换为驼峰格式的总体目标。

mapArrayKeys('underToCamel', array('foo_bar' => array ('baz_qux' => 0)));

关于注入性的说明。函数underToCamel不一定是单射的,所以你必须特别小心。您必须假设所有x_y和所有xY(其中Y是y的大写版本)恰好是x_yxYx_Y中的一个是一种下划线格式(同样遵循更多下划线)。

例如,underToCamel("foo_bar") == "fooBar"underToCamel("fooBar") == "fooBar"以及underToCamel("foo_Bar") == "fooBar"因此只有一个可以是有效的下划线格式。

嵌套函数的可读性

这是对 luqo33 的评论的回应。

  

我的意思太复杂了#39; (至少在我看来)就是这个   解决方案使用了许多嵌套函数(例如,调用了四个函数)   underToCamel,所有嵌套 - 阻碍了可读性。

有问题的代码就是这个。

lcfirst(implode('', array_map('ucfirst', explode('_', $str))));

我认为这是可读的。我确实认为这种风格对于PHP来说并不常见,我认为这就是PHP阅读器推迟的原因。

首先应该注意的是,嵌套函数实际上并不像你想象的那样异常。考虑数学表达式。

(-$b + sqrt($b*$b - 4*$a*$c)) / (2*$a)

这是一个使用大量嵌套函数的表达式:+, -, *, /。如果你假装你没有将BEDMAS(或等效物)嵌入你的潜意识中,这实际上是一个复杂的表达方式来理解 - 有隐含的规则你潜意识地应用于知道你首先用括号做的东西,然后乘法,等等。这一切看起来都不复杂,因为你已经学会了如何阅读这些表达,现在它已成为你的曲目的一部分。读取像我使用的表达式一样。

我可以重写表达式,以便每行使用一个函数。

$a = explode('_', $str);
$b = array_map('ucfirst', $a);
$c = implode('', $b);
$d = lcfirst($c);

现在从上到下读取执行顺序。我也可以把它写成从头到尾阅读。

lcfirst(
implode('',
array_map('ucfirst',
explode('_',
$str
))));

最后我可以把它写成从右到左或从里到外阅读(如果你考虑括号),这就是它最初编写的方式。

lcfirst(implode('', array_map('ucfirst', explode('_', $str))));

所有这些版本都使用一种名为 function composition 的简单模式,这是另一个易于阅读和理解的原因。通过函数组合,您可以构建一系列函数,其中每个函数都从前一个函数的输出中提供。

为了解释这种情况,我从左到右顺序的函数序列是explode '_', array_map 'ucfirst', implode '', lcfirst。从使用变量$a$d的版本可以清楚地看出它的工作方式。您将某些内容投入explode '_',其结果将传递到array_map 'ucfirst',然后传递到implode '',最后传递到lcfirst。您可以将其视为管道,装配线或类似的东西。

答案 2 :(得分:2)

您可以使用preg_replace_callback并更改所有密钥,而无需使用array_keysarray_combine循环使用每个密钥:

private function convertKeysToCamelCase($apiResponseArray) {
    $keys = preg_replace_callback('/_(.)/', function($m) {
        return strtoupper($m[1]);
    }), array_keys($apiResponseArray));

    return array_combine($keys, $apiResponseArray);
}

或没有正则表达式:

private function convertKeysToCamelCase($apiResponseArray) {
    $keys = array_map(function ($i) {
        $parts = explode('_', $i);
        return array_shift($parts). implode('', array_map('ucfirst', $parts));
    }, array_keys($apiResponseArray));

    return array_combine($keys, $apiResponseArray);
}

您可以修改第二个函数来处理多维数组:

private function convertKeysToCamelCase($apiResponseArray) {
    $keys = array_map(function ($i) use (&$apiResponseArray) {
        if (is_array($apiResponseArray[$i]))
            $apiResponseArray[$i] = $this->convertKeysToCamelCase($apiResponseArray[$i]);

        $parts = explode('_', $i);
        return array_shift($parts) . implode('', array_map('ucfirst', $parts));
    }, array_keys($apiResponseArray));

    return array_combine($keys, $apiResponseArray);
}

答案 3 :(得分:1)

尝试preg_replace_callback()

$key = preg_replace_callback('/_([a-z]*)/', function($matches) {
    return ucfirst($matches[1]);
}), $key);

一对夫妇注意到:

  • 您只需要查找[a-z],因为[A-Z]已经大写
  • * 0+重复用于我们遇到类似camel_$case的情况,我认为_仍然应该被替换
  • 此处的demo of the expression未在第一个匹配组中运行ucfirst()

答案 4 :(得分:1)

以下是以最简单的方式利用array_walk_recursive()preg_replace_callback方法的另一种方法:)

function convertKeysToCamelCase($array)
{
    $result = [];

    array_walk_recursive($array, function ($value, &$key) use (&$result) {
        $newKey = preg_replace_callback('/_([a-z])/', function ($matches) {
            return strtoupper($matches[1]);
        }, $key);

        $result[$newKey] = $value;
    });

    return $result;
}

答案 5 :(得分:0)

function convertToCamelCase($array){

           $finalArray     =       array();

           foreach ($array as $key=>$value):

                    if(strpos($key, "_"))
                            $key                    =       lcfirst(str_replace("_", "", ucwords($key, "_"))); //let's convert key into camelCase


                    if(!is_array($value))
                            $finalArray[$key]       =       $value;
                    else
                            $finalArray[$key]       =       $this->_convertToCamelCase($value );
            endforeach;

            return $finalArray;
}

convertToCamelCase会将数组键转换为驼峰大小写

例如,你可以使用它:

        $finalArray     =       convertToCamelCase($array);

 print_r(finalArray);