3

I have a $string:

'Name   Height  Weight
 John   177     142
 Jill   156     123
 Jacob  183     157'

And I'm turning it into an $array of the following structure:

Array (
    [0] => Array (
        ['Name'] => 'John'
        ['Height'] => '177'
        ['Weight'] => '142'
    )
    [1] = > Array (
        ['Name'] => 'Jill'
        ['Height'] => '156'
        ['Weight'] => '123'
    )
    [2] = > Array (
        ['Name'] => 'Jacob'
        ['Height'] => '183'
        ['Weight'] => '157'
    )
)

Using the following code:

$rows = explode("\n",$string); //creates an indexed array of rows as strings
$headers = explode("\t",$rows[0]); //creates an indexed array of headers as strings
$rows = array_slice($rows,1); //removes headers from $rows
$array = Array();
foreach($rows as $row) {
    $array[] = array_combine($headers, explode("\t",$row)); //creates associative arrays for each row
}

However, I cannot access the associative arrays inside of the indexed $array

For example, this doesn't work:

echo $array[0]['Name'];

Even though echo implode(', ', array_keys($array[0])); gives:

Name, Height, Weight

I've tried many different ways of accessing the associative arrays inside of the indexed array, but with no luck. What am I doing wrong?

EDIT:

So,

$string = "Name Height  Weight
John    177 142
Jill    156 123
Jacob‌​ 183 157";

Does not work, but

$string = "Name\tHeight\tWeight\nJohn\t177\t142\nJill\t156\t123\nJacob‌​‌​\t183\t157";

does...

So I suppose the question is: What's the difference? And how would I interpret the former string as the latter?

jeffbeene
  • 31
  • 4
  • Did you `print_r($array)`? What do you see? – u_mulder Mar 15 '17 at 06:53
  • Ermm nope, the array your code produces does not have that format – Hanky Panky Mar 15 '17 at 06:54
  • @u_mulder Yes, I see the array structure mentioned above (excluding the single quotes) – jeffbeene Mar 15 '17 at 06:55
  • @HankyPanky How come that structure is what print_r() and var_dump() show? – jeffbeene Mar 15 '17 at 06:56
  • https://eval.in/754774 – Hanky Panky Mar 15 '17 at 06:58
  • 1
    https://3v4l.org/NhXGD works fine with `tabs` as delimiters. Make sure that delimiters in your string are tabs. – u_mulder Mar 15 '17 at 07:00
  • @HankyPanky Thank you for taking the time to test it out. However, the actual data I'm using (financial data that I can't post) has the structure shown above, I'm sure of that. Both print_r() and var_dump() confirm that. I'm not sure why your test isn't splitting the contents of each row by the tabs. Is there anything else you can think of that might cause $array[0]['Name'] not to work? – jeffbeene Mar 15 '17 at 07:10
  • This post will help you to solve your problem : http://stackoverflow.com/questions/9554799/php-push-array-into-array-key-issue – Sweta Parmar Mar 15 '17 at 07:10
  • @u_mulder Thanks for running that test. As I said to HankyPanky, I'm certain that the structure is correct and that the explodes are working properly. Both print_r() and var_dump() confirm that, as does implode(', ', array_keys($array[0])) – jeffbeene Mar 15 '17 at 07:12
  • @SwetaParmar I'm not using array_push() or array_values(), I'm using $array[] = ... – jeffbeene Mar 15 '17 at 07:35
  • AFTER EDIT: if your string comes from an outside source you should assert that it really contains \t (which is the `TAB` character literal in `PHP`); in your first code we cannot tell if you have multiple `SPACEs` or one `TAB` character; in the latter, after the edit, you can be sure it has the expected format. Are you *really* sure the input string contains `TAB` and not `SPACEs`? – Constantin Galbenu Mar 15 '17 at 08:31

2 Answers2

1

Your code does not produce that array structure but it can be fixed like this:

$string = 'Name   Height  Weight
 John   177     142
 Jill   156     123
 Jacob  183     157';

$rows = explode("\n",$string); //creates an indexed array of rows as strings

$headers = preg_split("#\s+#",trim($rows[0], "\n\r\t ")); //creates an indexed array of headers as strings, by splitting by any white space
var_dump($headers);

$rows = array_slice($rows,1); //removes headers from $rows
$array = Array();
foreach($rows as $row) {
    $array[] = array_combine($headers, preg_split("#\s+#",trim($row, "\n\r\t "))); //creates associative arrays for each row, by splitting by any white space
}

var_dump($array);

This produces output:

array(3) {
  [0]=>
  string(4) "Name"
  [1]=>
  string(6) "Height"
  [2]=>
  string(6) "Weight"
}
array(3) {
  [0]=>
  array(3) {
    ["Name"]=>
    string(4) "John"
    ["Height"]=>
    string(3) "177"
    ["Weight"]=>
    string(3) "142"
  }
  [1]=>
  array(3) {
    ["Name"]=>
    string(4) "Jill"
    ["Height"]=>
    string(3) "156"
    ["Weight"]=>
    string(3) "123"
  }
  [2]=>
  array(3) {
    ["Name"]=>
    string(5) "Jacob"
    ["Height"]=>
    string(3) "183"
    ["Weight"]=>
    string(3) "157"
  }
}

The main ideas are that you must trim evey row string by any additional whitespaces and to split by the longest whitespace sequence.

Constantin Galbenu
  • 16,951
  • 3
  • 38
  • 54
  • Thank you. Give me a minute to wrap my head around this. In the meantime, any idea why print_r(), var_dump(), and implode(', ', array_keys($array[0])) are all suggesting that the array structure is correct? – jeffbeene Mar 15 '17 at 07:16
  • Okay, any reason why preg_split() is a better alternative to explode()? Unfortunately the real keys I'm using have spaces in them, so this won't work for me :/ – jeffbeene Mar 15 '17 at 07:26
  • I chose regular expression split because the input string can vary. If it does not vary, and always have the exact same structure (i.e. only one TAB character) then is not a better alternative in your case. – Constantin Galbenu Mar 15 '17 at 07:27
  • Okay. Unfortunately, I need to use the tabs as the delimiters since the keys have spaces in them. – jeffbeene Mar 15 '17 at 07:32
  • Then your code should work. I also have tested with tabs as other says and it worked. Try with this input string: `$string = "Name\tHeight\tWeight\nJohn\t177\t142\nJill\t156\t123\nJacob\t183\t157";` – Constantin Galbenu Mar 15 '17 at 07:36
  • @jeffbeene see here http://sandbox.onlinephpfunctions.com/code/958fa6775f483025cfd3db15e87f24ade6d2c79c – Constantin Galbenu Mar 15 '17 at 07:37
0
//Use following code it will work as your answer 
$string='Name   Height  Weight
 John   177     142
 Jill   156     123
 Jacob  183     157';

 $rows = explode("\n",$string); //creates an indexed array of rows as strings

$headers = explode("\t",$rows[0]); //creates an indexed array of headers as strings

$headers=array_filter(explode(" ",$headers[0])); ///t convert to space and filter remove empty element

$rows = array_slice($rows,1); //removes headers from $rows

$array = Array();
foreach($rows as $row) {
    $row=explode("\t",$row);
    $row=array_filter(explode(" ",$row[0]));

    $array[] = array_combine($headers,$row); //creates associative arrays for each row
}

//print_r($array);
echo $array[0]['Name'];
Afzal Patel
  • 124
  • 1
  • 6
  • Thank you. Now, what if I want spaces in my array keys? For example: "Person's Name" instead of "Name" – jeffbeene Mar 15 '17 at 07:30
  • If you want to use that type of the header ["Person's Name"] then the logic is wrong from the start. We need to use diffrent logic for that explode \n will give you space separate string in single row. – Afzal Patel Mar 15 '17 at 07:47
  • Okay, thanks. It seems my problem is not having `\t` in the string, but I'm not sure how to "replace" tabs with `\t`, if that makes sense... See the edit to my question. – jeffbeene Mar 15 '17 at 08:07