0

The ucwords function in PHP doesn't consider non-whitespace to be word boundaries. So, if I ucwords this-that, I get This-that. What I want is all words capitalized, such as This-That.

This is a straightforward function to do so. Anyone have suggestions to improve the runtime?

function ucallwords($s)
{
    $s = strtolower($s); // Just in case it isn't lowercased yet.
    $t = '';
    // Set t = only letters in s (spaces for all other characters)
    for($i=0; $i<strlen($s); $i++)
        if($s{$i}<'a' || $s{$i}>'z') $t.= ' ';
        else $t.= $s{$i};
    $t = ucwords($t);
    // Put the non-letter characters back in t
    for($i=0; $i<strlen($s); $i++)
        if($s{$i}<'a' || $s{$i}>'z') $t{$i} = $s{$i};
    return $t;
}

My gut feeling is that this could be done in a regular expression, but every time I start working on it, it gets complicated and I end up having to work on other things. I forget what I was doing and I have to start over. What I'd really like to hear is that PHP already has a good ucallwords function that I can use instead.

kainaw
  • 4,256
  • 1
  • 18
  • 38
  • I think for this case you'll have to use a little of regex, or you will have to do an array with all your possible delimiters – Emilio Gort Dec 08 '14 at 15:43
  • The code posted is invalid, you are missing variable identifiers for your string offsets. If you fix that your code may even work correctly. *Note: put the call to `strlen` outside of the loop decleration or it will be called in each iteration. If the length of the string does not change, these are redundant calls`* – Rangad Dec 08 '14 at 15:44
  • Yup. https://3v4l.org/408OY – mickmackusa Aug 13 '21 at 11:03

2 Answers2

0

Taken directly from ucwords manual:

By jmarois at ca dot ibm dot com

<?php
//FUNCTION

function ucname($string) {
    $string =ucwords(strtolower($string));

    foreach (array('-', '\'') as $delimiter) {
      if (strpos($string, $delimiter)!==false) {
        $string =implode($delimiter, array_map('ucfirst', explode($delimiter, $string)));
      }
    }
    return $string;
}
?>
<?php
//TEST

$names =array(
  'JEAN-LUC PICARD',
  'MILES O\'BRIEN',
  'WILLIAM RIKER',
  'geordi la forge',
  'bEvErly CRuSHeR'
);
foreach ($names as $name) { print ucname("{$name}\n"); }

//PRINTS:
/*
Jean-Luc Picard
Miles O'Brien
William Riker
Geordi La Forge
Beverly Crusher
*/
?>

You can add more delimiters in the for-each loop array if you want to handle more characters.

sjagr
  • 15,983
  • 5
  • 40
  • 67
Sablefoste
  • 4,032
  • 3
  • 37
  • 58
  • I feel that this would take longer in this case than the code I am already using. The foreach on the delimiters would essentially be: for every character that is not 'a' through 'z'. I considered something similar, but couldn't say "explode on everything except..." – kainaw Dec 08 '14 at 18:38
0

A regular expression is easy for this:

$s = 'this-that'; //Original string to uppercase.
$r = preg_replace('/(^|[^a-z])[a-z]/e', 'strtoupper("$0")', $s);

This assumes that $s is lower case. You can use a-zA-Z in the second line to match upper and lower case letters. Alternately, you can wrap $s in the second line with strtolower($s).

kainaw
  • 4,256
  • 1
  • 18
  • 38