Format A List Of Items In PHP

8th January 2010

It is usual when writing a list of items to separate each item with a comma, except the last two items, which are separated with the word "and". I recently needed to implement a function that took a string and converted it into a list of this type so I thought I would expand on it and post it here.

The function takes a single parameter, which can either be an array or a comma separated string. If an array is passed to the function then it is converted into a comma separated string and then passed onto the next part in the function. The function then removes any trailing commas, any commas that have nothing in between them and then makes sure that each comma has a single space after it. The final step is to replace the last comma with the word "and". Once the manipulation is complete then the resulting string is returned. If the string (after removing any trailing commas) doesn't contain any commas then it is simply returned.

Here is the function in full, will comments for each step.

  1. /**
  2.  * This function will take a string in the format of a single item or
  3.  * multiple items in the format 1,2,3,4,5 or an array of items.
  4.  * The output will be a readable set of items with the last two items
  5.  * separated by " and ".
  6.  *
  7.  * @param string|array $numbers The list of items as a string or array.
  8.  * @return string The formatted items.
  9.  */
  10. function formatItems($numbers)
  11. {
  12. if (is_array($numbers)) {
  13. // If numbers is an array then implode it into a comma separated string.
  14. $numbers = implode(',', $numbers);
  15. }
  16.  
  17. if (is_string($numbers)) {
  18. // Make sure all commas have a single space character after them.
  19. $numbers = preg_replace("/(\s*?,\s*)/", ", ", $numbers);
  20. // Remove any spare commas
  21. $numbers = preg_replace("/(,\s)+/", ", ", $numbers);
  22. // The string contains commas, find the last comma in the string.
  23. $lastCommaPos = strrpos($numbers, ',') - strlen($numbers);
  24. // Replace the last ocurrance of a comma with " and "
  25. $numbers = substr($numbers, 0, $lastCommaPos) . str_replace(',', ' and', substr($numbers, $lastCommaPos));
  26. }
  27. return $numbers;
  28. }

Here are a few examples of this function in action.

  1. echo formatItems('1');
  2. echo formatItems('1,2');
  3. echo formatItems('1,2,3,4,5,6,7');
  4. echo formatItems(range(1,6));
  5. echo formatItems(range('a','g'));
  6. echo formatItems('sdfgdf g,sdf, g,dfg,df,g ,df g,df,g ,d fg');
  7. echo formatItems('1.45/76,5/,85/6.,45./6,456');
  8. echo formatItems('sdfah, ,,, ,, ,,,, , , , [email protected])_}_:{>9l,65653224,253,4,236,56,98./,978/59');
  9. echo formatItems('4575,8 56,456,36,45656 ,, , 4, 56, 546, 546, , 6, 456, , ');

This code produces the following output.

  1. 1
  2. 1 and 2
  3. 1, 2, 3, 4, 5, 6 and 7
  4. 1, 2, 3, 4, 5 and 6
  5. a, b, c, d, e, f and g
  6. sdfgdf g, sdf, g, dfg, df, g, df g, df, g and d fg
  7. 1.45/76, 5/, 85/6., 45./6 and 456
  8. sdfah, [email protected])_}_:{>9l, 65653224, 253, 4, 236, 56, 98./ and 978/59
  9. 4575, 8 56, 456, 36, 45656, 4, 56, 546, 546, 6 and 456

UPDATE: 08/05/2010

Thanks to Carl for finding a little bug with regards to how commas in messy strings are looked at within the function. I had a quick look at code I wrote to clean up a list of user inputted items and included it in this code. Here is the new version of the function.

  1. /**
  2.  * This function will take a string in the format of a single item or
  3.  * multiple items in the format 1,2,3,4,5 or an array of items.
  4.  * The output will be a readable set of items with the last two items
  5.  * separated by " and ".
  6.  *
  7.  * @param string|array $numbers The list of items as a string or array.
  8.  * @return string The formatted items.
  9.  */
  10. function formatItems($numbers)
  11. {
  12. if (is_array($numbers)) {
  13. // If numbers is an array then implode it into a comma separated string.
  14. $numbers = implode(',', $numbers);
  15. }
  16.  
  17. if (is_string($numbers)) {
  18. /*
  19. Make sure all commas have a single space character after them and that
  20. there are no double commas in the string.
  21. */
  22. $numbers = trim($numbers);
  23. $patterns[0] = '/\s*,\s*/';
  24. $patterns[1] = '/,{2,}/';
  25. $patterns[2] = '/,+$/';
  26. $patterns[3] = '/^,+/';
  27. $patterns[4] = '/,/';
  28. $replacements[0] = ',';
  29. $replacements[1] = ',';
  30. $replacements[2] = '';
  31. $replacements[3] = '';
  32. $replacements[4] = ', ';
  33. $numbers= preg_replace($patterns, $replacements, $numbers);
  34.  
  35. // The string contains commas, find the last comma in the string.
  36. $lastCommaPos = strrpos($numbers, ',') - strlen($numbers);
  37.  
  38. // Replace the last ocurrance of a comma with " and "
  39. $numbers = substr($numbers, 0, $lastCommaPos) . str_replace(',', ' and ', substr($numbers, $lastCommaPos));
  40. }
  41. return $numbers;
  42. }

Comments

Permalink
Hi, Thanks for putting together these tutorials. They're a great combination of educational value and practicality as well. I've spent much of Saturday afternoon and early evening looking through them but my wife needs a bit of attention. I couldn't get the last array to work (4575, 8 56, 456, 36, 45656, 4, 56, 546, 546, 6 and 456), instead I got; 4575, 8 56, 456, 36, 45656, 4, 56, 546, 546, 6, 456 and I managed to fudge it by putting in an extra check; // remove any simulutaneous , space sequence $numbers = preg_replace("/,\s,\s/", "", $numbers); It's not very pretty but it works, and I guess I've got some way to go! Thanks again.

Submitted by Carl on Sat, 05/08/2010 - 20:03

Permalink
Hi Carl, I'm glad you find this site useful! I have put a lot of work into this site so it's nice to get some positive feedback :) Thanks for telling me about the problem you found with the function, I had a play around with your suggestion and it worked very well. I remembered writing some code that cleaned up a comma separated list so I dug that out and replaced the comma filtering in this function. Rather than delete and replace the original function I just added an update to the bottom. Feel free to add any more comments if you find any more problems. Phil

Submitted by philipnorton42 on Sat, 05/08/2010 - 22:23

Permalink
first, thank you so much for posting this. i'm quite new to php and would not have been able to do this on my own. and, of course, i learned a great deal just from reading the code. i do have one very noobish question: how do i call the function and store the comma separated list in a variable (as text)? i thought something like: $list = formatItems($assignees); might work but i'm not having any luck. the $assignees variable is a text array. thanks!!

Submitted by john on Thu, 05/20/2010 - 13:55

Permalink
That would work. The $list variable will contain your formatted list of items. :)

Submitted by philipnorton42 on Thu, 05/20/2010 - 22:30

Permalink
For some reason, when I do it that way, it doesn't recognize that I'm calling a function -- even though I placed it in the file with my other functions that ARE recognized.

Submitted by neurotopia on Thu, 05/20/2010 - 23:03

Permalink
It worked for me when I tried it just now, here's the code I used (with the function pasted in at the top).
  1. $assignees = '1,,67 ,8,8,67,53,45,45, 34,5q34,dguhdfg ,sdfghdfgh,sdf s,df g,sdf ,,dfg ';
  2.  
  3. $list = formatItems($assignees);
  4.  
  5. echo $list;

Submitted by philipnorton42 on Fri, 05/21/2010 - 09:11

Permalink
hmmmm... this is soooo kicking my butt. i'm pulling the array from a mysql database with: foreach($_POST['uids'] as $userid) { $database->executeUpdate("INSERT INTO bookings (eid, uid) VALUES (?, ?)", $_POST['bookedeventid'], $userid); $emailaddress[] = $database->executeQueryRows("SELECT email FROM users WHERE uid =?", $userid); } executeUpdate and executeQueryRows are functions in the same file as the formatItems function, so i know the file is getting loaded. they replace the "?" with the values at the end of each statement (i.e. $_POST['bookedeventid] and $userid. does the fact that i'm pulling the array from a mysql table matter?

Submitted by neurotopia on Sun, 05/23/2010 - 02:50

Permalink
nevermind, i figured out what i did wrong. the function works, though for some reason the value that is returned is still "Array".

Submitted by neurotopia on Sun, 05/23/2010 - 02:54

Permalink
you were right and it works fine. the fault was mine. feel free to delete my posts.

Submitted by neurotopia on Sun, 05/23/2010 - 20:28

Permalink
Well I'm happy you managed to solve your problem! It's all part of programming I suppose. I have lost count of the number of times I've sat in front of code going "why doesn't this work" only to find that I had been unbelievably stupid. :)

Submitted by philipnorton42 on Sun, 05/23/2010 - 21:42

Permalink

Hi Phil,

Thanks heaps for this! I was wondering if you might be able to help me with something similar - I want to automatically create list items

  • when ever some enters a line break. So when the user enters

    Item 1

    Item2

    Item3

    The script changes it to:

  • item 1
  • item 2
  • item 3
  •  

    Any idea of how I would go about this? Thanks heaps!

    Submitted by Adam on Tue, 12/13/2011 - 13:09

    Permalink

    Should be quite simple. All you need to do is replace line breaks with the string '

  • ' and then wrap the whole thing in a list item to ensure the correct markup.
  • Submitted by philipnorton42 on Tue, 12/13/2011 - 16:32

    Add new comment

    The content of this field is kept private and will not be shown publicly.