Capitalize last names including exceptions like mccall => McCall
Asked Answered
S

4

0

I am having trouble with the capitalization of names using PHP. There are some names that have 2 capital letters in them (ex: McCall). When storing a users name that registers for our website, we run the following code:

$name = ucwords(strtolower(trim($_SESSION['last_name']))) ;

What this does is change 'mccall' to 'Mccall'. What we need is a way to check if the first 2 letters begin with 'Mc' and if so, the 3rd letter will be capitalized as well changing the name to 'McCall'.

Ski answered 4/3, 2012 at 2:35 Comment(8)
How about just letting users specify their own name without change? My last name is O'Hara. Some people's last name is O'hara. You won't be able to tell the difference. How about Mac- instead of Mc- names? Last names containing a hyphen?Moderator
I ran into this same issue a while back and decided to just allow users to specify their own case for names, both for the reasons @minitech has given, and also the fact that, if the user wants, they can have an all caps name.Fireproof
Believe me, I wish people would enter their name correctly, but they do not. I am not worried about any other name other than 'Mc'.Ski
@three3, who decides the proper representation of a name other than the person who it belongs to?Suzannesuzerain
@three3: That seems a somewhat arrogant approach to take to your users.Electromagnet
If you want to just catch the lazy typist, then I would check to see if a name is all lowercase or all uppercase, and then do your transformation. If somebody writes "mccall" or "MCCALL" then they deserve whatever mistakes your "correction" creates. (There's nothing wrong with making sure your site doesn't look like it's being used by illiterate children.)Malchus
I agree with minitech, Oli Charlesworth and JamWaffles, as most people will spell their names the way they want. However, if you are bent on doing this, you could set up an array with the different variations find the matching alpha patterns and offer suggestions for the user to choose from (including the one they typed in).Semination
An excellent/versatile answer at https://mcmap.net/q/360710/-title-case-a-string-containing-one-or-more-last-names-while-handling-names-with-apostrophes/2943403Sexuality
I
1
$name = 'mccall';
$name = ucwords(strtolower(trim($name))) ;

if (strpos($name, 'Mc') === 0) {
    $name = 'Mc' . ucwords(substr($name, 2, strlen($name)));
}
echo $name; // McCall
Insubstantial answered 4/3, 2012 at 2:50 Comment(0)
M
3

Here's a solution that will just catch Mc, if that's really all you're interested in:

function capitalizeLastName($name) {
    $result = ucwords(strtolower(trim($_SESSION['last_name'])));

    if(substr($result, 0, 2) === 'Mc') {
        $result[2] = strtoupper($result[2]); // Yes, this works in PHP!
    }

    return $result;
}
Moderator answered 4/3, 2012 at 2:47 Comment(1)
To the anonymous editor: no, it won’t, as seen in the first example of the documentation for ucwords.Moderator
S
3

Just FYI, I have a REALLY nice function for capitalizing a lot more than just names. It also does titles, phrases, etc...

It takes a string parameter and a boolean. The bool is TRUE if you're capitalizing a name, and FALSE or nothing if it's a title, phrase, etc...

Use is as simple as:

capitalize('mccall', TRUE); // result 'McCall'
capitalize('merry christmas and happy holidays!'); // result 'Merry Christmas and Happy Holidays!'
capitalize('jd mckinstry', TRUE); // result 'JD McKinstry'

The fun ction!

function capitalize($str, $is_name=FALSE) {
    $str = trim(stripcslashes($str));

    // exceptions to standard case conversion
    if ($is_name) {
        $all_uppercase = '';//'Aj|Jd';
        $all_lowercase = 'De La|De Las|Der|Van De|Van Der|Vit De|Von|Or|And|Van ';
    }
    else {  // addresses, essay titles ... and anything else
        $all_uppercase = 'Po|Rr|Se|Sw|Ne|Nw';
        $all_lowercase = 'A|And|As|By|In|Of|Or|To';
    }

    $prefixes = 'Mc';
    $suffixes = "'S";

    // captialize all first letters
    $str = preg_replace('/\\b(\\w)/e', 'strtoupper("$1")', strtolower(trim($str)));

    if ($all_uppercase) {   // capitalize acronymns and initialisms e.g. PHP
        $str = preg_replace("/\\b($all_uppercase)\\b/e", 'strtoupper("$1")', $str);
    }

    if ($is_name) {
        if (strpos($str, " ") !== FALSE) {
            $ara = explode(" ", $str);
            foreach ($ara as $k => $v) {
                if ($k != count($ara)-1 && !preg_match("/[aeiouyAEIOUY]/", $v)) $ara[$k] = strtoupper($v);
            }
            $str = implode(" ", $ara);
        }
        elseif (!preg_match("/[aeiouy]/", $str)) {
            $str = strtoupper($str);
        }
    }

    if ($all_lowercase) {   // decapitalize short words e.g. and
        if ($is_name) { // all occurences will be changed to lowercase
            $str = preg_replace("/\\b($all_lowercase)\\b/e", 'strtolower("$1")', $str);
        }
        else {  // first and last word will not be changed to lower case (i.e. titles)
            $str = preg_replace("/(?<=\\W)($all_lowercase)(?=\\W)/e", 'strtolower("$1")', $str);
        }
    }

    if ($prefixes) {    // capitalize letter after certain name prefixes e.g 'Mc'
        $str = preg_replace("/\\b($prefixes)(\\w)/e", '"$1".strtoupper("$2")', $str);
    }

    if ($suffixes) {    // decapitalize certain word suffixes e.g. 's
        $str = preg_replace("/(\\w)($suffixes)\\b/e", '"$1".strtolower("$2")', $str);
    }

    //  Mac Exceptions
    if (strpos($str, "Macd") === FALSE || strpos($str, "Macv") === FALSE) {
        $str = preg_replace("/Macd/", 'MacD', $str);
        $str = preg_replace("/Macv/", 'MacV', $str);
    }

    return trim(stripcslashes($str));
}

As some of you might notice, this was originally taken from the PHP site, but I've since nurtured it and matured it into a much more useful and "intelligent" method!

Silurian answered 28/6, 2013 at 16:23 Comment(1)
The preg_replace is deprecated! Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead! Update your code.Protomartyr
I
1
$name = 'mccall';
$name = ucwords(strtolower(trim($name))) ;

if (strpos($name, 'Mc') === 0) {
    $name = 'Mc' . ucwords(substr($name, 2, strlen($name)));
}
echo $name; // McCall
Insubstantial answered 4/3, 2012 at 2:50 Comment(0)
D
1

I found this answer as I was searching on the function found in the PHP manual, as answerd by SpYk3HH.

The preg_replace has been deprecated as correctly noticed by Michelangelo. To save others some time here the renewed function.

Plus some additions to support Dutch names:

<?php

function capitalize($str, $is_name = FALSE) {

  $mylist = "S|‘s|‘t|A|Aan|Aan ‘t|Aan De|Aan Den|Aan Der|Aan Het|Aan T|Af|Al|Am|"
      . "Am De|Auf|Auf Dem|Auf Den|Auf Der|Auf Ter|Aus|Aus ‘m|Aus Dem|Aus Den|"
      . "Aus Der|Aus M|Ben|Bij|Bij ‘t|Bij De|Bij Den|Bij Het|Bij T|Bin|Boven D|"
      . "Boven D’|D|D’|Da|Dal|Dal’|Dalla|Das|De|De Die|De Die Le|De L|De L’|"
      . "De La|De Las|De Le|De Van Der|Deca|Degli|Dei|Del|Della|Den|Der|Des|"
      . "Di|Die Le|Do|Don|Dos|Du|El|Het|I|Im|In|In ‘t|In De|In Den|In Der|"
      . "In Het|In T|L|L’|La|Las|Le|Les|Lo|Los|Of|Onder|Onder ‘t|Onder De|"
      . "Onder Den|Onder Het|Onder T|Op|Op ‘t|Op De|Op Den|Op Der|Op Gen|Op Het|"
      . "Op T|Op Ten|Over|Over ‘t|Over De|Over Den|Over Het|Over T|S’|T|Te|Ten|"
      . "Ter|Tho|Thoe|Thor|To|Toe|Tot|Uijt|Uijt ‘t|Uijt De|Uijt Den|Uijt Te De|"
      . "Uijt Ten|Uit|Uit ‘t|Uit De|Uit Den|Uit Het|Uit T|Uit Te De|Uit Ten|"
      . "Unter|Van|Van ‘t|Van De|Van De L|Van De L’|Van Den|Van Der|Van Gen|"
      . "Van Het|Van La|Van T|Van Ter|Van Van De|Ver|Vom|Von|Von ‘t|Von Dem|"
      . "Von Den|Von Der|Von T|Voor|Voor ‘t|Voor De|Voor Den|Voor In ‘t|"
      . "Voor In T|Vor|Vor Der|Zu|Zum|Zur|Vit De|Or|And|Van|En";



  $str = trim($str);
  $str = stripcslashes($str);

  // exceptions to standard case conversion
  if ($is_name) {
    $all_uppercase = ''; //'Aj|Jd';
    $all_lowercase = $mylist;
  }
  else {  // addresses, essay titles ... and anything else
    $all_uppercase = 'Po|Rr|Se|Sw|Ne|Nw';
    $all_lowercase = 'A|And|As|By|In|Of|Or|To';
  }

  $prefixes = 'Mc';
  $suffixes = "'S";

  // captialize all first letters
  $str = preg_replace_callback('/\\b(\\w)/', function($m) {
    return strtoupper($m[1]);
  }, strtolower(trim($str)));

  if ($all_uppercase) {   // capitalize acronymns and initialisms e.g. PHP
    $str = preg_replace("/\\b($all_uppercase)\\b/", function($m) {
      return strtoupper($m[1]);
    }, $str);
  }

  if ($is_name) {
    if (strpos($str, " ") !== FALSE) {
      $ara = explode(" ", $str);
      foreach ($ara as $k => $v) {
        if ($k != count($ara) - 1 && !preg_match("/[aeiouyAEIOUY]/", $v))
          $ara[$k] = strtoupper($v);
      }
      $str = implode(" ", $ara);
    }
    elseif (!preg_match("/[aeiouy]/", $str)) {
      $str = strtoupper($str);
    }
  }

  if ($all_lowercase) {   // decapitalize short words e.g. and
    if ($is_name) { // all occurences will be changed to lowercase
      $str = preg_replace_callback("/\\b($all_lowercase)\\b/", function($m) {
        return strtolower($m[1]);
      }, $str);
    }
    else {  // first and last word will not be changed to lower case (i.e. titles)
      $str = preg_replace_callback("/(?<=\\W)($all_lowercase)(?=\\W)/", function($m) {
        return strtolower($m[1]);
      }, $str);
    }
  }

  if ($prefixes) {    // capitalize letter after certain name prefixes e.g 'Mc'
    $str = preg_replace_callback("/\\b($prefixes)(\\w)/", function($m) {
      return $m[1] . strtoupper($m[2]);
    }
        , $str);
  }

  if ($suffixes) {    // decapitalize certain word suffixes e.g. 's
    $str = preg_replace_callback("/(\\w)($suffixes)\\b/", function($m) {
      return $m[1] . strtoupper($m[2]);
    }, $str);
  }

  //  Mac Exceptions
  if (strpos($str, "Macd") === FALSE || strpos($str, "Macv") === FALSE) {
    //$str = preg_replace_callback("/Macd/", 'MacD', $str);
    //$str = preg_replace_callback("/Macv/", 'MacV', $str);
  }

  return trim(stripcslashes($str));
}

//Array containing names to test
$testnames = [
  'van der vaart',
  'van vollenhoven',
  "van 't zandt",
  'van het zand',
  'el hamdoie',
  'van der Rooi-van Velzen',
  'Zuidewijn - van rooien',
  'teggelen onder t boven',
  "guido op 't drooge",
  "friso van drooge",
  'Zuidewijn - van rooien',
  'teggelen onder t boven',
  'ZUID-HOLLAND',
  "'s hertogen-bosch",
  "De Rooi Van Zuidewijn",
  "van onder",
  "Van Der Wijk-Zeewuster",
  "de Vries-van der Leest",
  "Den Oudsten - van 't Veldt",
  "Hare Koninklijke Hoogheid Alexia Juliana Marcela Laurentien Prinses der Nederlanden, Prinses van Oranje-Nassau",
  "Hare Koninklijke Hoogheid Máxima, Prinses der Nederlanden, Prinses van Oranje-Nassau, Mevrouw van Amsberg",
  "van Lippe-Biesterfeld van Vollenhoven",
];

foreach ($testnames as $name) {

  //First convert name to uppercase to get rid of the correct caps
  $name = strtoupper($name);
  //Output the capitalized name
  echo $name;
  echo " = ";
  //See output of function
  echo capitalize($name, TRUE);
  //Set br tag to get the next test name on next line
  echo "<br />";
}
Derby answered 18/7, 2017 at 12:45 Comment(3)
van der Vaart should start with a capital V, unless a first name was provided. And for Belgiums other rules apply.Jari
Correct function above only applies to Dutch names, I use this function to convert the lastname. If you use it without a first name, or initials just use ucfirst() at the lastname and it will be correct.Derby
But apart from that so far well usable function for Dutch namesJari

© 2022 - 2024 — McMap. All rights reserved.