1

It feels like that problem has already been solved but my search did not find a "good" solution. I have a time critical app and need to convert a typical string into an assoc array:

"appliCAation=webCALL&Arg1=ABC&arG2=xyZ&someMore=Dec-1950"

I know I can use parse_str() for that but I would like to "normalize" the user input so that all keys are always uppercase and all values are always lowercase (and vice versa, if possible done by parameter and NOT widen the footprint of the code).

Since array_change_key_case() does not work recursively, I search for an elegant way with few lines of code and efficient performance.

At the moment I use parse_str( strtolower( $input ), $arr ); and then loop (recursively) the array to change the keys. Unfortunately that needs two methods and "many" code lines.

Any faster / better / smaller solution for that?

AbraCadaver
  • 78,200
  • 7
  • 66
  • 87
jwka
  • 115
  • 7
  • Once the problem is broken down ("parse first"), it's easy to find solutions relating to each task: [array_change_key_case](https://www.php.net/manual/en/function.array-change-key-case.php) , https://stackoverflow.com/q/25068571/2864740 , etc. – user2864740 May 23 '20 at 17:46
  • Oh, I see.. some upper and some lower.. :| – user2864740 May 23 '20 at 17:54
  • 1
    You mention _recursively_ twice but haven't shown an array that would need to be recursed. – AbraCadaver May 23 '20 at 17:55

1 Answers1

1

Flip your logic and uppercase everything and then recursively lower case the values:

parse_str(strtoupper($string), $array);    
array_walk_recursive($array, function(&$v, $k) { $v = strtolower($v); });

This will work for multiple dimensions such as:

$string = "appliCAation=webCALL&Arg1=ABC&arG2=xyZ&someMore=Dec-1950&a[yZ][zzz]=efG";

Yielding:

Array
(
    [APPLICAATION] => webcall
    [ARG1] => abc
    [ARG2] => xyz
    [SOMEMORE] => dec-1950
    [A] => Array
        (
            [YZ] => Array
                (
                    [ZZZ] => efg
                )
        )
)

After rereading the question I see you want to be able to change or control whether the keys and values are uppercase or lowercase. You can use() a parameters array to use as function names:

$params = ['key' => 'strtoupper', 'val' => 'strtolower'];
parse_str($params['key']($string), $array);    
array_walk_recursive($array, function(&$v, $k) use($params){ $v = $params['val']($v); });

To change just the keys, I would use a Regular Expression on the original string:

$keys = 'strtoupper';
$string = preg_replace_callback('/[^=&]*=/', function($m) use($keys) { return $keys($m[0]); }, $string);
parse_str($string, $array);

[^=&]*= is a character class [] matching characters that are ^ not = or & 0 or more times * followed by =.

And finally, here is one that will do keys and values if you supply a function name (notice val is empty), if not then it is not transformed:

$params = ['key' => 'strtoupper', 'val' => ''];
$string = preg_replace_callback('/([^=&]*)=([^=&]*)/',
                                function($m) use($params) {
                                    return (empty($params['key']) ? $m[1] : $params['key']($m[1]))
                                           .'='.
                                           (empty($params['val']) ? $m[2] : $params['val']($m[2]));
                                }, $string);
parse_str($string, $array);
AbraCadaver
  • 78,200
  • 7
  • 66
  • 87
  • one last question ... any possibility to keep the values "as is" as an "alternative"? I understand that the first step is to change the whole string to what the keys should look like and then use array_walk to "correct" the values. What If I would NOT want to alter the values and only alter the keys? – jwka May 23 '20 at 19:32
  • Edited with a regex. – AbraCadaver May 23 '20 at 19:50
  • NP, added another one ;-) – AbraCadaver May 23 '20 at 20:27
  • wow. thanks. great work. I need to deal with / learn regex more intensively! – jwka May 24 '20 at 19:24