递归地将多维数组中的所有键转换为snake_case

发布于 2024-08-05 23:58:19 字数 486 浏览 3 评论 0原文

我正在尝试将多维数组的键从camelCase或StudlyCase/PascalCase转换为snake_case,但增加了一些复杂性,即某些键有一个我想删除的前导感叹号。

例如:

$array = array(
  '!AccountNumber' => '00000000',
  'Address' => array(
    '!Line1' => '10 High Street',
    '!line2' => 'London'));

我想转换为:

$array = array(
  'account_number' => '00000000',
  'address' => array(
    'line1' => '10 High Street',
    'line2' => 'London'));

我现实生活中的数组很大,而且有很多层次。

I am trying to convert the keys of a multi-dimensional array from camelCase or StudlyCase/PascalCase to snake_case, with the added complication that some keys have a leading exclamation mark that I'd like to be removed.

For example:

$array = array(
  '!AccountNumber' => '00000000',
  'Address' => array(
    '!Line1' => '10 High Street',
    '!line2' => 'London'));

I would like to convert to:

$array = array(
  'account_number' => '00000000',
  'address' => array(
    'line1' => '10 High Street',
    'line2' => 'London'));

My real-life array is huge and goes many levels deep.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

谷夏 2024-08-12 23:58:19

这是我使用的修改后的函数,取自灵魂合并的响应:

function transformKeys(&$array)
{
  foreach (array_keys($array) as $key):
    # Working with references here to avoid copying the value,
    # since you said your data is quite large.
    $value = &$array[$key];
    unset($array[$key]);
    # This is what you actually want to do with your keys:
    #  - remove exclamation marks at the front
    #  - camelCase to snake_case
    $transformedKey = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', ltrim($key, '!')));
    # Work recursively
    if (is_array($value)) transformKeys($value);
    # Store with new key
    $array[$transformedKey] = $value;      
    # Do not forget to unset references!
    unset($value);
  endforeach;
}

This is the modified function I have used, taken from soulmerge's response:

function transformKeys(&$array)
{
  foreach (array_keys($array) as $key):
    # Working with references here to avoid copying the value,
    # since you said your data is quite large.
    $value = &$array[$key];
    unset($array[$key]);
    # This is what you actually want to do with your keys:
    #  - remove exclamation marks at the front
    #  - camelCase to snake_case
    $transformedKey = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', ltrim($key, '!')));
    # Work recursively
    if (is_array($value)) transformKeys($value);
    # Store with new key
    $array[$transformedKey] = $value;      
    # Do not forget to unset references!
    unset($value);
  endforeach;
}
于我来说 2024-08-12 23:58:19

这是亚伦的更通用的版本。这样你就可以为所有按键插入你想要操作的功能。我假设了一个静态类。

public static function toCamelCase ($string) {
  $string_ = str_replace(' ', '', ucwords(str_replace('_',' ', $string)));
  return lcfirst($string_);
}

public static function toUnderscore ($string) {
  return strtolower(preg_replace('/([^A-Z])([A-Z])/', "$1_$2", $string));
}

// http://stackoverflow.com/a/1444929/632495
function transformKeys($transform, &$array) {
  foreach (array_keys($array) as $key):
    # Working with references here to avoid copying the value,
    # since you said your data is quite large.
    $value = &$array[$key];
    unset($array[$key]);
    # This is what you actually want to do with your keys:
    #  - remove exclamation marks at the front
    #  - camelCase to snake_case
    $transformedKey = call_user_func($transform, $key);
    # Work recursively
    if (is_array($value)) self::transformKeys($transform, $value);
    # Store with new key
    $array[$transformedKey] = $value;
    # Do not forget to unset references!
    unset($value);
  endforeach;
}

public static function keysToCamelCase ($array) {
  self::transformKeys(['self', 'toCamelCase'], $array);
  return $array;
}

public static function keysToUnderscore ($array) {
  self::transformKeys(['self', 'toUnderscore'], $array);
  return $array;
}

Here's a more generalized version of Aaron's. This way you can just plug the function you want to be operated on for all keys. I assumed a static class.

public static function toCamelCase ($string) {
  $string_ = str_replace(' ', '', ucwords(str_replace('_',' ', $string)));
  return lcfirst($string_);
}

public static function toUnderscore ($string) {
  return strtolower(preg_replace('/([^A-Z])([A-Z])/', "$1_$2", $string));
}

// http://stackoverflow.com/a/1444929/632495
function transformKeys($transform, &$array) {
  foreach (array_keys($array) as $key):
    # Working with references here to avoid copying the value,
    # since you said your data is quite large.
    $value = &$array[$key];
    unset($array[$key]);
    # This is what you actually want to do with your keys:
    #  - remove exclamation marks at the front
    #  - camelCase to snake_case
    $transformedKey = call_user_func($transform, $key);
    # Work recursively
    if (is_array($value)) self::transformKeys($transform, $value);
    # Store with new key
    $array[$transformedKey] = $value;
    # Do not forget to unset references!
    unset($value);
  endforeach;
}

public static function keysToCamelCase ($array) {
  self::transformKeys(['self', 'toCamelCase'], $array);
  return $array;
}

public static function keysToUnderscore ($array) {
  self::transformKeys(['self', 'toUnderscore'], $array);
  return $array;
}
冰火雁神 2024-08-12 23:58:19

您可以在数组键上运行 foreach,这样您就可以就地重命名键:

function transformKeys(&$array) {
    foreach (array_keys($array) as $key) {
        # This is what you actually want to do with your keys:
        #  - remove exclamation marks at the front
        #  - camelCase to snake_case
        $transformedKey = ltrim($key, '!');
        $transformedKey = strtolower($transformedKey[0] . preg_replace('/[A-Z]/', '_$0', substr($transformedKey, 1)));
        # Store with new key
        $array[$transformedKey] = &$array[$key];
        unset($array[$key]);
        # Work recursively
        if (is_array($array[$transformedKey])) {
            transformKeys($array[$transformedKey]);
        }
    }
}

You can run a foreach on the arrays keys, this way you'll rename the keys in-place:

function transformKeys(&$array) {
    foreach (array_keys($array) as $key) {
        # This is what you actually want to do with your keys:
        #  - remove exclamation marks at the front
        #  - camelCase to snake_case
        $transformedKey = ltrim($key, '!');
        $transformedKey = strtolower($transformedKey[0] . preg_replace('/[A-Z]/', '_$0', substr($transformedKey, 1)));
        # Store with new key
        $array[$transformedKey] = &$array[$key];
        unset($array[$key]);
        # Work recursively
        if (is_array($array[$transformedKey])) {
            transformKeys($array[$transformedKey]);
        }
    }
}
⊕婉儿 2024-08-12 23:58:19

虽然这可能不是问题的准确答案,但我想将其发布在这里,供那些正在寻找优雅的解决方案来更改多维 PHP 数组中的关键案例的人们使用。您还可以调整它以更改一般的数组键。只需调用不同的函数而不是 array_change_key_case_recursive

// converts all keys in a multidimensional array to lower or upper case
function array_change_key_case_recursive($arr, $case=CASE_LOWER)
{
  return array_map(function($item)use($case){
    if(is_array($item))
        $item = array_change_key_case_recursive($item, $case);
    return $item;
  },array_change_key_case($arr, $case));
}

Although this may not be an exact answer to the question, but I wanted to post it here for people who are searching for elegant solution for changing key case in multidimensional PHP arrays. You can also adapt it for changing array keys in general. Just call a different function instead of array_change_key_case_recursive

// converts all keys in a multidimensional array to lower or upper case
function array_change_key_case_recursive($arr, $case=CASE_LOWER)
{
  return array_map(function($item)use($case){
    if(is_array($item))
        $item = array_change_key_case_recursive($item, $case);
    return $item;
  },array_change_key_case($arr, $case));
}
债姬 2024-08-12 23:58:19

创建一个像这样的函数:

   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;
}

并像这样调用它:

$newArray = convertToCamelCase($array);

对于工作示例请参阅此

Create a function like:

   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;
}

and call this like:

$newArray = convertToCamelCase($array);

for working example see this

多孤肩上扛 2024-08-12 23:58:19
<?php

class Maison {
    
    public $superficieAll_1;
    public $addressBook;
    
}

class Address { 
    public $latitudeAmi;
    public $longitude;
}

$maison = new Maison();
$maison->superficieAll_1 = 80;
$maison->addressBook->longitudeAmi = 2;
$maison->addressBook->latitude = 4;

$returnedArray = transformation($maison);
print_r($returnedArray);

function transformation($obj){
    //object to array
    $array = json_decode(json_encode((array) $obj),true);
    //now transform all array keys
    return transformKeys($array);
}    

function transformKeys($array)
{
    foreach ($array as $key => $value){
        // echo "$key <br>";
        unset($array[$key]);
        $transformedKey = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', ltrim($key, '!')));
        $array[$transformedKey] = $value;  
        // echo "$transformedKey update <br>";
        if (is_array($value)) {
            $array[$transformedKey] = transformKeys($value);
        }
    }
    return $array;
}
<?php

class Maison {
    
    public $superficieAll_1;
    public $addressBook;
    
}

class Address { 
    public $latitudeAmi;
    public $longitude;
}

$maison = new Maison();
$maison->superficieAll_1 = 80;
$maison->addressBook->longitudeAmi = 2;
$maison->addressBook->latitude = 4;

$returnedArray = transformation($maison);
print_r($returnedArray);

function transformation($obj){
    //object to array
    $array = json_decode(json_encode((array) $obj),true);
    //now transform all array keys
    return transformKeys($array);
}    

function transformKeys($array)
{
    foreach ($array as $key => $value){
        // echo "$key <br>";
        unset($array[$key]);
        $transformedKey = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', ltrim($key, '!')));
        $array[$transformedKey] = $value;  
        // echo "$transformedKey update <br>";
        if (is_array($value)) {
            $array[$transformedKey] = transformKeys($value);
        }
    }
    return $array;
}
卸妝后依然美 2024-08-12 23:58:19

我想说,您必须编写一个函数来复制数组(一级),并在任何值是数组(递归函数)时让该函数调用自身。

  • 使用trim()可以轻松删除感叹号
  • 中间的大写字符之前可以使用正则表达式
  • 添加下划线添加下划线后,整个键可以转换为小写

您到底需要什么具体帮助?

I'd say you would have to write a function to copy the array (one level) and have that function call itself if any of the values is an array (a recursive function).

  • The exclamation marks are easily removed using trim()
  • The underscore before the uppercase characters in the middle can be added using a regex
  • After adding the underscore, the whole key can be converted to lower case

What exactly do you need any specific help with?

寻找一个思念的角度 2024-08-12 23:58:19

为了避免改变原始数组并返回具有重新格式化键的新数组,请使用递归函数而不通过引用进行修改,并在每个级别上返回新数组。

代码:(演示)

function snakeCaseKeys($array): array
{
    $result = [];
    foreach ($array as $k => $v) {
        $k = strtolower(
                 preg_replace(
                     '/[a-z]\K(?=[A-Z])/',
                     '_',
                     ltrim($k, '!')
                 )
             );
        $result[$k] = is_array($v) ? snakeCaseKeys($v) : $v;
    }
    return $result;
}

var_export(
    snakeCaseKeys($array)
);

或在不生成新数组的情况下改变每个级别:(Demo)

function snakeCaseKeys($array): array
{
    foreach ($array as $k => $v) {
        unset($array[$k]);
        $k = strtolower(
                 preg_replace(
                     '/[a-z]\K(?=[A-Z])/',
                     '_',
                     ltrim($k, '!')
                 )
             );
        $array[$k] = is_array($v) ? snakeCaseKeys($v) : $v;
    }
    return $array;
}

测试数据:

$array = [
    '!AccountNumber' => '00000000',
    'Address' => [
        '!Line1' => '10 High Street',
        'deeperSubArrayToRekey' => [
            'camelCase' => 'starts with lowercase',
            'PascalCase' => 'starts with uppercase',
            'StudlyCase' => 'is a synonym for PascalCase',
            '!!!!snake_case' => 'is already fully lowercase',
        ],
        '!line2' => 'London',
        'Line1' => 'will overwrite 10 High Street',
    ]
];

输出:

array (
  'account_number' => '00000000',
  'address' => 
  array (
    'line1' => 'will overwrite 10 High Street',
    'deeper_sub_array_to_rekey' => 
    array (
      'camel_case' => 'starts with lowercase',
      'pascal_case' => 'starts with uppercase',
      'studly_case' => 'is a synonym for PascalCase',
      'snake_case' => 'is already fully lowercase',
    ),
    'line2' => 'London',
  ),
)

即使使用引用修改(如 aaronrussell 的答案),foreach 循环仍在创建数据副本并且仍然必须生成新密钥并销毁旧密钥 - 没有就地修改密钥的快捷方式。

To avoid mutating the original array and return a new array with reformatted keys, use a recursive function without modifying by reference and return the new array on every level.

Code: (Demo)

function snakeCaseKeys($array): array
{
    $result = [];
    foreach ($array as $k => $v) {
        $k = strtolower(
                 preg_replace(
                     '/[a-z]\K(?=[A-Z])/',
                     '_',
                     ltrim($k, '!')
                 )
             );
        $result[$k] = is_array($v) ? snakeCaseKeys($v) : $v;
    }
    return $result;
}

var_export(
    snakeCaseKeys($array)
);

Or mutate each level in place without generating a new array: (Demo)

function snakeCaseKeys($array): array
{
    foreach ($array as $k => $v) {
        unset($array[$k]);
        $k = strtolower(
                 preg_replace(
                     '/[a-z]\K(?=[A-Z])/',
                     '_',
                     ltrim($k, '!')
                 )
             );
        $array[$k] = is_array($v) ? snakeCaseKeys($v) : $v;
    }
    return $array;
}

Test data:

$array = [
    '!AccountNumber' => '00000000',
    'Address' => [
        '!Line1' => '10 High Street',
        'deeperSubArrayToRekey' => [
            'camelCase' => 'starts with lowercase',
            'PascalCase' => 'starts with uppercase',
            'StudlyCase' => 'is a synonym for PascalCase',
            '!!!!snake_case' => 'is already fully lowercase',
        ],
        '!line2' => 'London',
        'Line1' => 'will overwrite 10 High Street',
    ]
];

Output:

array (
  'account_number' => '00000000',
  'address' => 
  array (
    'line1' => 'will overwrite 10 High Street',
    'deeper_sub_array_to_rekey' => 
    array (
      'camel_case' => 'starts with lowercase',
      'pascal_case' => 'starts with uppercase',
      'studly_case' => 'is a synonym for PascalCase',
      'snake_case' => 'is already fully lowercase',
    ),
    'line2' => 'London',
  ),
)

Even if modification by reference is used (like in aaronrussell's answer), the foreach loop is still creating copies of data and new keys still have to be generated and old keys destroyed -- there is no shortcut to modify keys in-place.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文