Correct Name Capitalization in PHP

One annoying scenario is when you let users enter their names and then you need to output their names nicely, for example in a newsletter. Some users simply enter their names in upper/lowercase, but obviously when you address them you can’t do the same. On the other hand PHP’s ucfirst() and ucwords() functions are too naive for proper capitalization.

Let’s consider a few use cases:

 Original ucwords(strtolower($str))proper
michael o’carrolMichael O’carrolMichael O’Carrol
lucas l’amourLucas L’amourLucas l’Amour
george d’onofrioGeorge D’onofrioGeorge d’Onofrio
william stanley iiiWilliam Stanley IiiWilliam Stanley III
UNITED STATES OF AMERICAUnited States Of AmericaUnited States of America
t. von lieres und wilkauT. Von Lieres Und WilkauT. von Lieres und Wilkau
paul van der knaapPaul Van Der KnaapPaul van der Knaap
jean-luc picardJean-luc PicardJean-Luc Picard
JOHN MCLARENJohn MclarenJohn McLaren
hENRIC vIIIHenric ViiiHenric VIII
VAsco da GAmaVasco Da GamaVasco da Gama

You get the picture.

To make this work we need to observe three things:

  • some words should be separated not just by space, but also by hypens and apostrophes.
  • some words (especially “of” variations in different languages) must always be lower case.
  • On the contrary, a some words like roman numerals must always be upper case.

This is what I came up with:

function titleCase($string) 
{
	$word_splitters = array(' ', '-', "O'", "L'", "D'", 'St.', 'Mc');
	$lowercase_exceptions = array('the', 'van', 'den', 'von', 'und', 'der', 'de', 'da', 'of', 'and', "l'", "d'");
	$uppercase_exceptions = array('III', 'IV', 'VI', 'VII', 'VIII', 'IX');

	$string = strtolower($string);
	foreach ($word_splitters as $delimiter)
	{ 
		$words = explode($delimiter, $string); 
		$newwords = array(); 
		foreach ($words as $word)
		{ 
			if (in_array(strtoupper($word), $uppercase_exceptions))
				$word = strtoupper($word);
			else
			if (!in_array($word, $lowercase_exceptions))
				$word = ucfirst($word); 

			$newwords[] = $word;
		}

		if (in_array(strtolower($delimiter), $lowercase_exceptions))
			$delimiter = strtolower($delimiter);

		$string = join($delimiter, $newwords); 
	} 
	return $string; 
}

This should work for most cases. I did not test it for non-latin alphabets.

Armand Niculescu

Armand Niculescu

Senior Full-stack developer and graphic designer with over 25 years of experience, Armand took on many challenges, from coding to project management and marketing.

2 Responses

  1. Wow. I just had a client meeting where she complained about people entering all caps and making her pretty website look ugly. I can’t wait to give this a try! Thanks!

Comments are closed.