views:

251

answers:

3

I am trying to convert the keys of a multi-dimensional array from CamelCase to snake_case, with the added complication that some keys have an exclamation mark that I'd like 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. Any help with how to approach this is much appreciated!

A: 

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?

jeroen
+1  A: 

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]);
        }
    }
}
soulmerge
Thanks for this, it's put me in the right direction but there were a couple of issues.First of all the $transformedKey was spitting out some odd results so I have slightly modified that line. Also the recursive if statement needs to be positioned above the line storing the new array key for some reason.I'll post my modified function below.
aaronrussell
Just noticed, should be fixed now.
soulmerge
A: 

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