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

luq*_*o33 5 php regex arrays 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;
}
Run Code Online (Sandbox Code Playgroud)

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

你有没有办法整理这种方法?更重要的是,只需一次调用即可完成同样的操作preg_match吗?那会是什么样子?

axi*_*iac 11

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

但是从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))));
Run Code Online (Sandbox Code Playgroud)

要么

$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))));
Run Code Online (Sandbox Code Playgroud)

要么

$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
);
Run Code Online (Sandbox Code Playgroud)

选择你最喜欢的!


Cas*_*yte 6

您可以使用preg_replace_callback和更改所有键,而无需在每个使用array_keys和上循环array_combine

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

    return array_combine($keys, $apiResponseArray);
}
Run Code Online (Sandbox Code Playgroud)

或没有正则表达式:

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);
}
Run Code Online (Sandbox Code Playgroud)

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

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);
}
Run Code Online (Sandbox Code Playgroud)


eri*_*sco 5

我可以很快发现两个独立的任务。一种是将字符串转换为驼峰格式,另一种是映射多维数组的键。这些任务彼此无关,因此最好将它们作为单独的功能来实现。

让我们从一个高阶函数开始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;
}
Run Code Online (Sandbox Code Playgroud)

有一些我认为不那么重要的繁琐部分。你可能不想在参数上做类型提示,好吧。也许你更喜欢 if/then/else 而不是三元运算符,好吧。重要的是,mapArrayKeys您可以将任何(内射)映射函数应用于数组键。

第二个任务是将字符串转换为驼峰式大小写。您可以为此使用 PCRE 函数,这很好。我将用于explode进行拆分。

function underToCamel($str) {
  return lcfirst(implode('', array_map('ucfirst', explode('_', $str))));
}
Run Code Online (Sandbox Code Playgroud)

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

mapArrayKeys('underToCamel', array('foo_bar' => array ('baz_qux' => 0)));
Run Code Online (Sandbox Code Playgroud)

关于注入性的注释。该函数underToCamel不一定是单射的,因此您必须特别小心。您必须假设对于所有x_y和所有xY(其中 Y 是 y 的大写版本)x_yxY,x_Y中的一个是下划线格式(更多下划线之后也是如此)。

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

嵌套函数的可读性

这是对luqo33评论的回应

我所说的“太复杂”(至少在我看来)是指这个解决方案使用了很多嵌套函数(例如在 underToCamel 中调用的四个函数,全部嵌套 - 阻碍了可读性)。

有问题的代码行是这样的。

lcfirst(implode('', array_map('ucfirst', explode('_', $str))));
Run Code Online (Sandbox Code Playgroud)

我争辩说这是可读的。我承认这种风格不是 PHP 的典型风格,我认为这就是 PHP 读者可能会被推迟的原因。

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

(-$b + sqrt($b*$b - 4*$a*$c)) / (2*$a)
Run Code Online (Sandbox Code Playgroud)

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

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

$a = explode('_', $str);
$b = array_map('ucfirst', $a);
$c = implode('', $b);
$d = lcfirst($c);
Run Code Online (Sandbox Code Playgroud)

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

lcfirst(
implode('',
array_map('ucfirst',
explode('_',
$str
))));
Run Code Online (Sandbox Code Playgroud)

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

lcfirst(implode('', array_map('ucfirst', explode('_', $str))));
Run Code Online (Sandbox Code Playgroud)

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

为了解释这种情况,我从左到右的函数序列是explode '_', array_map 'ucfirst', implode '', lcfirst. 从使用变量$a$d. 你把东西扔进去explode '_',结果被传入array_map 'ucfirst',然后传入implode '',最后传入lcfirst。您可以将其视为管道、装配线或类似的东西。