<p>Does anyone have a trusted Proper Case or PCase algorithm (similar to a UCase or Upper)?  I'm looking for something that takes a value such as <code>"GEORGE BURDELL"</code> or <code>"george burdell"</code> and turns it into <code>"George Burdell"</code>.</p>

<p>I have a simple one that handles the simple cases.  The ideal would be to have something that can handle things such as <code>"O'REILLY"</code> and turn it into <code>"O'Reilly"</code>, but I know that is tougher.</p>

<p>I am mainly focused on the English language if that simplifies things.</p>

<hr>

<p><strong>UPDATE:</strong> I'm using C# as the language, but I can convert from almost anything (assuming like functionality exists).</p>

<p>I agree that the McDonald's scneario is a tough one.  I meant to mention that along with my O'Reilly example, but did not in the original post.</p>

[{'answer_id': 32189, 'author': 'Konrad Rudolph', 'author_id': 1968, 'author_profile': 'https://Stackoverflow.com/users/1968', 'pm_score': 1, 'selected': False, 'text': "<p>What programming language do you use? Many languages allow callback functions for regular expression matches. These can be used to propercase the match easily. The regular expression that would be used is quite simple, you just have to match all word characters, like so:</p>\n\n<pre><code>/\\w+/\n</code></pre>\n\n<p>Alternatively, you can already extract the first character to be an extra match:</p>\n\n<pre><code>/(\\w)(\\w*)/\n</code></pre>\n\n<p>Now you can access the first character and successive characters in the match separately. The callback function can then simply return a concatenation of the hits. In pseudo Python (I don't actually know Python):</p>\n\n<pre><code>def make_proper(match):\n    return match[1].to_upper + match[2]\n</code></pre>\n\n<p>Incidentally, this would also handle the case of “O'Reilly” because “O” and “Reilly” would be matched separately and both propercased. There are however other special cases that are not handled well by the algorithm, e.g. “McDonald's” or generally any apostrophed word. The algorithm would produce “Mcdonald'S” for the latter. A special handling for apostrophe could be implemented but that would interfere with the first case. Finding a thereotical perfect solution isn't possible. In practice, it might help considering the length of the part after the apostrophe.</p>\n"}, {'answer_id': 32236, 'author': 'JimmyJ', 'author_id': 2083, 'author_profile': 'https://Stackoverflow.com/users/2083', 'pm_score': 0, 'selected': False, 'text': '<p>a simple way to capitalise the first letter of each word (seperated by a space)</p>\n\n<pre><code>$words = explode(” “, $string);\nfor ($i=0; $i&lt;count($words); $i++) {\n$s = strtolower($words[$i]);\n$s = substr_replace($s, strtoupper(substr($s, 0, 1)), 0, 1);\n$result .= “$s “;\n}\n$string = trim($result);\n</code></pre>\n\n<p>in terms of catching the "O\'REILLY" example you gave\nsplitting the string on both spaces and \' would not work as it would capitalise any letter that appeared after a apostraphe i.e. the s in Fred\'s</p>\n\n<p>so i would probably try something like </p>\n\n<pre><code>$words = explode(” “, $string);\nfor ($i=0; $i&lt;count($words); $i++) {\n\n$s = strtolower($words[$i]);\n\nif (substr($s, 0, 2) === "o\'"){\n$s = substr_replace($s, strtoupper(substr($s, 0, 3)), 0, 3);\n}else{\n$s = substr_replace($s, strtoupper(substr($s, 0, 1)), 0, 1);\n}\n$result .= “$s “;\n}\n$string = trim($result);\n</code></pre>\n\n<p>This should catch O\'Reilly, O\'Clock, O\'Donnell etc hope it helps</p>\n\n<p>Please note this code is untested.</p>\n'}, {'answer_id': 32249, 'author': 'GateKiller', 'author_id': 383, 'author_profile': 'https://Stackoverflow.com/users/383', 'pm_score': -1, 'selected': False, 'text': '<p>You do not mention which language you would like the solution in so here is some pseudo code.</p>\n\n<pre><code>Loop through each character\n    If the previous character was an alphabet letter\n        Make the character lower case\n    Otherwise\n        Make the character upper case\nEnd loop\n</code></pre>\n'}, {'answer_id': 32254, 'author': 'Jeff Atwood', 'author_id': 1, 'author_profile': 'https://Stackoverflow.com/users/1', 'pm_score': 2, 'selected': False, 'text': '<p>There\'s also this neat Perl script for title-casing text.</p>\n\n<p><a href="http://daringfireball.net/2008/08/title_case_update" rel="nofollow noreferrer">http://daringfireball.net/2008/08/title_case_update</a></p>\n\n<blockquote>\n<pre><code>#!/usr/bin/perl\n\n#     This filter changes all words to Title Caps, and attempts to be clever\n# about *un*capitalizing small words like a/an/the in the input.\n#\n# The list of "small words" which are not capped comes from\n# the New York Times Manual of Style, plus \'vs\' and \'v\'. \n#\n# 10 May 2008\n# Original version by John Gruber:\n# http://daringfireball.net/2008/05/title_case\n#\n# 28 July 2008\n# Re-written and much improved by Aristotle Pagaltzis:\n# http://plasmasturm.org/code/titlecase/\n#\n#   Full change log at __END__.\n#\n# License: http://www.opensource.org/licenses/mit-license.php\n#\n\n\nuse strict;\nuse warnings;\nuse utf8;\nuse open qw( :encoding(UTF-8) :std );\n\n\nmy @small_words = qw( (?&lt;!q&amp;)a an and as at(?!&amp;t) but by en for if in of on or the to v[.]? via vs[.]? );\nmy $small_re = join \'|\', @small_words;\n\nmy $apos = qr/ (?: [\'’] [[:lower:]]* )? /x;\n\nwhile ( &lt;&gt; ) {\n  s{\\A\\s+}{}, s{\\s+\\z}{};\n\n  $_ = lc $_ if not /[[:lower:]]/;\n\n  s{\n      \\b (_*) (?:\n          ( (?&lt;=[ ][/\\\\]) [[:alpha:]]+ [-_[:alpha:]/\\\\]+ |   # file path or\n            [-_[:alpha:]]+ [@.:] [-_[:alpha:]@.:/]+ $apos )  # URL, domain, or email\n          |\n          ( (?i: $small_re ) $apos )                         # or small word (case-insensitive)\n          |\n          ( [[:alpha:]] [[:lower:]\'’()\\[\\]{}]* $apos )       # or word w/o internal caps\n          |\n          ( [[:alpha:]] [[:alpha:]\'’()\\[\\]{}]* $apos )       # or some other word\n      ) (_*) \\b\n  }{\n      $1 . (\n        defined $2 ? $2         # preserve URL, domain, or email\n      : defined $3 ? "\\L$3"     # lowercase small word\n      : defined $4 ? "\\u\\L$4"   # capitalize word w/o internal caps\n      : $5                      # preserve other kinds of word\n      ) . $6\n  }xeg;\n\n\n  # Exceptions for small words: capitalize at start and end of title\n  s{\n      (  \\A [[:punct:]]*         # start of title...\n      |  [:.;?!][ ]+             # or of subsentence...\n      |  [ ][\'"“‘(\\[][ ]*     )  # or of inserted subphrase...\n      ( $small_re ) \\b           # ... followed by small word\n  }{$1\\u\\L$2}xig;\n\n  s{\n      \\b ( $small_re )      # small word...\n      (?= [[:punct:]]* \\Z   # ... at the end of the title...\n      |   [\'"’”)\\]] [ ] )   # ... or of an inserted subphrase?\n  }{\\u\\L$1}xig;\n\n  # Exceptions for small words in hyphenated compound words\n  ## e.g. "in-flight" -&gt; In-Flight\n  s{\n      \\b\n      (?&lt;! -)                 # Negative lookbehind for a hyphen; we don\'t want to match man-in-the-middle but do want (in-flight)\n      ( $small_re )\n      (?= -[[:alpha:]]+)      # lookahead for "-someword"\n  }{\\u\\L$1}xig;\n\n  ## # e.g. "Stand-in" -&gt; "Stand-In" (Stand is already capped at this point)\n  s{\n      \\b\n      (?&lt;!…)                  # Negative lookbehind for a hyphen; we don\'t want to match man-in-the-middle but do want (stand-in)\n      ( [[:alpha:]]+- )       # $1 = first word and hyphen, should already be properly capped\n      ( $small_re )           # ... followed by small word\n      (?! - )                 # Negative lookahead for another \'-\'\n  }{$1\\u$2}xig;\n\n  print "$_";\n}\n\n__END__\n</code></pre>\n</blockquote>\n\n<p>But it sounds like by proper case you mean.. for people\'s names <em>only</em>.</p>\n'}, {'answer_id': 33168, 'author': 'Markus Olsson', 'author_id': 2114, 'author_profile': 'https://Stackoverflow.com/users/2114', 'pm_score': 5, 'selected': True, 'text': '<p>Unless I\'ve misunderstood your question I don\'t think you need to roll your own, the TextInfo class can do it for you.</p>\n\n<pre><code>using System.Globalization;\n\nCultureInfo.InvariantCulture.TextInfo.ToTitleCase("GeOrGE bUrdEll")\n</code></pre>\n\n<p>Will return "George Burdell. And you can use your own culture if there\'s some special rules involved.</p>\n\n<p><strong>Update:</strong> <a href="https://stackoverflow.com/users/1684/michael-wolfenden">Michael</a> (in a comment to this answer) pointed out that this will not work if the input is all caps since the method will assume that it is an acronym. The naive workaround for this is to .ToLower() the text before submitting it to ToTitleCase.</p>\n'}, {'answer_id': 33291, 'author': 'ljs', 'author_id': 3394, 'author_profile': 'https://Stackoverflow.com/users/3394', 'pm_score': 1, 'selected': False, 'text': '<p>Here\'s a perhaps naive C# implementation:-</p>\n\n<pre><code>public class ProperCaseHelper {\n  public string ToProperCase(string input) {\n    string ret = string.Empty;\n\n    var words = input.Split(\' \');\n\n    for (int i = 0; i &lt; words.Length; ++i) {\n      ret += wordToProperCase(words[i]);\n      if (i &lt; words.Length - 1) ret += " ";\n    }\n\n    return ret;\n  }\n\n  private string wordToProperCase(string word) {\n    if (string.IsNullOrEmpty(word)) return word;\n\n    // Standard case\n    string ret = capitaliseFirstLetter(word);\n\n    // Special cases:\n    ret = properSuffix(ret, "\'");\n    ret = properSuffix(ret, ".");\n    ret = properSuffix(ret, "Mc");\n    ret = properSuffix(ret, "Mac");\n\n    return ret;\n  }\n\n  private string properSuffix(string word, string prefix) {\n    if(string.IsNullOrEmpty(word)) return word;\n\n    string lowerWord = word.ToLower(), lowerPrefix = prefix.ToLower();\n    if (!lowerWord.Contains(lowerPrefix)) return word;\n\n    int index = lowerWord.IndexOf(lowerPrefix);\n\n    // If the search string is at the end of the word ignore.\n    if (index + prefix.Length == word.Length) return word;\n\n    return word.Substring(0, index) + prefix +\n      capitaliseFirstLetter(word.Substring(index + prefix.Length));\n  }\n\n  private string capitaliseFirstLetter(string word) {\n    return char.ToUpper(word[0]) + word.Substring(1).ToLower();\n  }\n}\n</code></pre>\n'}, {'answer_id': 485362, 'author': 'Community', 'author_id': -1, 'author_profile': 'https://Stackoverflow.com/users/-1', 'pm_score': 0, 'selected': False, 'text': '<p>Kronoz, thank you. I found in your function that the line:</p>\n\n<pre><code>`if (!lowerWord.Contains(lowerPrefix)) return word`;\n</code></pre>\n\n<p>must say</p>\n\n<pre><code>if (!lowerWord.StartsWith(lowerPrefix)) return word;\n</code></pre>\n\n<p>so "información" is not changed to "InforMacIón"</p>\n\n<p>best,</p>\n\n<p>Enrique</p>\n'}, {'answer_id': 3553524, 'author': 'Dasith Wijes', 'author_id': 422427, 'author_profile': 'https://Stackoverflow.com/users/422427', 'pm_score': 0, 'selected': False, 'text': '<p>I use this as the textchanged event handler of text boxes. Support entry of "McDonald"    </p>\n\n<pre><code>Public Shared Function DoProperCaseConvert(ByVal str As String, Optional ByVal allowCapital As Boolean = True) As String\n    Dim strCon As String = ""\n    Dim wordbreak As String = " ,.1234567890;/\\-()#$%^&amp;*€!~+=@"\n    Dim nextShouldBeCapital As Boolean = True\n\n    \'Improve to recognize all caps input\n    \'If str.Equals(str.ToUpper) Then\n    \'    str = str.ToLower\n    \'End If\n\n    For Each s As Char In str.ToCharArray\n\n        If allowCapital Then\n            strCon = strCon &amp; If(nextShouldBeCapital, s.ToString.ToUpper, s)\n        Else\n            strCon = strCon &amp; If(nextShouldBeCapital, s.ToString.ToUpper, s.ToLower)\n        End If\n\n        If wordbreak.Contains(s.ToString) Then\n            nextShouldBeCapital = True\n        Else\n            nextShouldBeCapital = False\n        End If\n    Next\n\n    Return strCon\nEnd Function\n</code></pre>\n'}, {'answer_id': 6576464, 'author': 'Colin', 'author_id': 645902, 'author_profile': 'https://Stackoverflow.com/users/645902', 'pm_score': 4, 'selected': False, 'text': '<p><a href="https://stackoverflow.com/users/388520/zwol">@zwol</a>: I\'ll post it as a separate reply.</p>\n<p>Here\'s an example based on <a href="https://stackoverflow.com/users/3394/ljs">ljs</a>\'s <a href="https://stackoverflow.com/a/33291">post</a>.</p>\n<pre><code>void Main()\n{\n    List&lt;string&gt; names = new List&lt;string&gt;() {\n        &quot;bill o\'reilly&quot;, \n        &quot;johannes diderik van der waals&quot;, \n        &quot;mr. moseley-williams&quot;, \n        &quot;Joe VanWyck&quot;, \n        &quot;mcdonald\'s&quot;, \n        &quot;william the third&quot;, \n        &quot;hrh prince charles&quot;, \n        &quot;h.r.m. queen elizabeth the third&quot;,\n        &quot;william gates, iii&quot;, \n        &quot;pope leo xii&quot;,\n        &quot;a.k. jennings&quot;\n    };\n    \n    names.Select(name =&gt; name.ToProperCase()).Dump();\n}\n\n// http://stackoverflow.com/questions/32149/does-anyone-have-a-good-proper-case-algorithm\npublic static class ProperCaseHelper\n{\n    public static string ToProperCase(this string input)\n    {\n        if (IsAllUpperOrAllLower(input))\n        {\n            // fix the ALL UPPERCASE or all lowercase names\n            return string.Join(&quot; &quot;, input.Split(\' \').Select(word =&gt; wordToProperCase(word)));\n        }\n        else\n        {\n            // leave the CamelCase or Propercase names alone\n            return input;\n        }\n    }\n\n    public static bool IsAllUpperOrAllLower(this string input)\n    {\n        return (input.ToLower().Equals(input) || input.ToUpper().Equals(input));\n    }\n\n    private static string wordToProperCase(string word)\n    {\n        if (string.IsNullOrEmpty(word)) return word;\n\n        // Standard case\n        string ret = capitaliseFirstLetter(word);\n\n        // Special cases:\n        ret = properSuffix(ret, &quot;\'&quot;);   // D\'Artagnon, D\'Silva\n        ret = properSuffix(ret, &quot;.&quot;);   // ???\n        ret = properSuffix(ret, &quot;-&quot;);       // Oscar-Meyer-Weiner\n        ret = properSuffix(ret, &quot;Mc&quot;, t =&gt; t.Length &gt; 4);      // Scots\n        ret = properSuffix(ret, &quot;Mac&quot;, t =&gt; t.Length &gt; 5);     // Scots except Macey\n\n        // Special words:\n        ret = specialWords(ret, &quot;van&quot;);     // Dick van Dyke\n        ret = specialWords(ret, &quot;von&quot;);     // Baron von Bruin-Valt\n        ret = specialWords(ret, &quot;de&quot;);\n        ret = specialWords(ret, &quot;di&quot;);\n        ret = specialWords(ret, &quot;da&quot;);      // Leonardo da Vinci, Eduardo da Silva\n        ret = specialWords(ret, &quot;of&quot;);      // The Grand Old Duke of York\n        ret = specialWords(ret, &quot;the&quot;);     // William the Conqueror\n        ret = specialWords(ret, &quot;HRH&quot;);     // His/Her Royal Highness\n        ret = specialWords(ret, &quot;HRM&quot;);     // His/Her Royal Majesty\n        ret = specialWords(ret, &quot;H.R.H.&quot;);  // His/Her Royal Highness\n        ret = specialWords(ret, &quot;H.R.M.&quot;);  // His/Her Royal Majesty\n\n        ret = dealWithRomanNumerals(ret);   // William Gates, III\n\n        return ret;\n    }\n\n    private static string properSuffix(string word, string prefix, Func&lt;string, bool&gt; condition = null)\n    {\n        if (string.IsNullOrEmpty(word)) return word;\n        if (condition != null &amp;&amp; ! condition(word)) return word;\n        \n        string lowerWord = word.ToLower();\n        string lowerPrefix = prefix.ToLower();\n\n        if (!lowerWord.Contains(lowerPrefix)) return word;\n\n        int index = lowerWord.IndexOf(lowerPrefix);\n\n        // If the search string is at the end of the word ignore.\n        if (index + prefix.Length == word.Length) return word;\n\n        return word.Substring(0, index) + prefix +\n            capitaliseFirstLetter(word.Substring(index + prefix.Length));\n    }\n\n    private static string specialWords(string word, string specialWord)\n    {\n        if (word.Equals(specialWord, StringComparison.InvariantCultureIgnoreCase))\n        {\n            return specialWord;\n        }\n        else\n        {\n            return word;\n        }\n    }\n\n    private static string dealWithRomanNumerals(string word)\n    {\n        // Roman Numeral parser thanks to [djk](https://stackoverflow.com/users/785111/djk)\n        // Note that it excludes the Chinese last name Xi\n        return new Regex(@&quot;\\b(?!Xi\\b)(X|XX|XXX|XL|L|LX|LXX|LXXX|XC|C)?(I|II|III|IV|V|VI|VII|VIII|IX)?\\b&quot;, RegexOptions.IgnoreCase).Replace(word, match =&gt; match.Value.ToUpperInvariant());\n    }\n\n    private static string capitaliseFirstLetter(string word)\n    {\n        return char.ToUpper(word[0]) + word.Substring(1).ToLower();\n    }\n\n}\n</code></pre>\n'}, {'answer_id': 22058928, 'author': 'gillytech', 'author_id': 1332828, 'author_profile': 'https://Stackoverflow.com/users/1332828', 'pm_score': 2, 'selected': False, 'text': '<p>I wrote this today to implement in an app I\'m working on. I think this code is pretty self explanatory with comments. It\'s not 100% accurate in all cases but it will handle most of your western names easily.</p>\n\n<p>Examples:</p>\n\n<p><code>mary-jane =&gt; Mary-Jane</code></p>\n\n<p><code>o\'brien =&gt; O\'Brien</code></p>\n\n<p><code>Joël VON WINTEREGG =&gt; Joël von Winteregg</code></p>\n\n<p><code>jose de la acosta =&gt; Jose de la Acosta</code></p>\n\n<p>The code is extensible in that you may add any string value to the arrays at the top to suit your needs. Please study it and add any special feature that may be required.</p>\n\n<pre><code>function name_title_case($str)\n{\n  // name parts that should be lowercase in most cases\n  $ok_to_be_lower = array(\'av\',\'af\',\'da\',\'dal\',\'de\',\'del\',\'der\',\'di\',\'la\',\'le\',\'van\',\'der\',\'den\',\'vel\',\'von\');\n  // name parts that should be lower even if at the beginning of a name\n  $always_lower   = array(\'van\', \'der\');\n\n  // Create an array from the parts of the string passed in\n  $parts = explode(" ", mb_strtolower($str));\n\n  foreach ($parts as $part)\n  {\n    (in_array($part, $ok_to_be_lower)) ? $rules[$part] = \'nocaps\' : $rules[$part] = \'caps\';\n  }\n\n  // Determine the first part in the string\n  reset($rules);\n  $first_part = key($rules);\n\n  // Loop through and cap-or-dont-cap\n  foreach ($rules as $part =&gt; $rule)\n  {\n    if ($rule == \'caps\')\n    {\n      // ucfirst() words and also takes into account apostrophes and hyphens like this:\n      // O\'brien -&gt; O\'Brien || mary-kaye -&gt; Mary-Kaye\n      $part = str_replace(\'- \',\'-\',ucwords(str_replace(\'-\',\'- \', $part)));\n      $c13n[] = str_replace(\'\\\' \', \'\\\'\', ucwords(str_replace(\'\\\'\', \'\\\' \', $part)));\n    }\n    else if ($part == $first_part &amp;&amp; !in_array($part, $always_lower))\n    {\n      // If the first part of the string is ok_to_be_lower, cap it anyway\n      $c13n[] = ucfirst($part);\n    }\n    else\n    {\n      $c13n[] = $part;\n    }\n  }\n\n  $titleized = implode(\' \', $c13n);\n\n  return trim($titleized);\n}\n</code></pre>\n'}, {'answer_id': 45774526, 'author': 'user326608', 'author_id': 326608, 'author_profile': 'https://Stackoverflow.com/users/326608', 'pm_score': 2, 'selected': False, 'text': '<p>I did a quick C# port of <a href="https://github.com/tamtamchik/namecase" rel="nofollow noreferrer">https://github.com/tamtamchik/namecase</a>, which is based on Lingua::EN::NameCase.</p>\n\n<pre class="lang-cs prettyprint-override"><code>public static class CIQNameCase\n{\n    static Dictionary&lt;string, string&gt; _exceptions = new Dictionary&lt;string, string&gt;\n        {\n            {@"\\bMacEdo"     ,"Macedo"},\n            {@"\\bMacEvicius" ,"Macevicius"},\n            {@"\\bMacHado"    ,"Machado"},\n            {@"\\bMacHar"     ,"Machar"},\n            {@"\\bMacHin"     ,"Machin"},\n            {@"\\bMacHlin"    ,"Machlin"},\n            {@"\\bMacIas"     ,"Macias"},\n            {@"\\bMacIulis"   ,"Maciulis"},\n            {@"\\bMacKie"     ,"Mackie"},\n            {@"\\bMacKle"     ,"Mackle"},\n            {@"\\bMacKlin"    ,"Macklin"},\n            {@"\\bMacKmin"    ,"Mackmin"},\n            {@"\\bMacQuarie"  ,"Macquarie"}\n        };\n\n    static Dictionary&lt;string, string&gt; _replacements = new Dictionary&lt;string, string&gt;\n        {\n            {@"\\bAl(?=\\s+\\w)"         , @"al"},        // al Arabic or forename Al.\n            {@"\\b(Bin|Binti|Binte)\\b" , @"bin"},       // bin, binti, binte Arabic\n            {@"\\bAp\\b"                , @"ap"},        // ap Welsh.\n            {@"\\bBen(?=\\s+\\w)"        , @"ben"},       // ben Hebrew or forename Ben.\n            {@"\\bDell([ae])\\b"        , @"dell$1"},    // della and delle Italian.\n            {@"\\bD([aeiou])\\b"        , @"d$1"},       // da, de, di Italian; du French; do Brasil\n            {@"\\bD([ao]s)\\b"          , @"d$1"},       // das, dos Brasileiros\n            {@"\\bDe([lrn])\\b"         , @"de$1"},      // del Italian; der/den Dutch/Flemish.\n            {@"\\bEl\\b"                , @"el"},        // el Greek or El Spanish.\n            {@"\\bLa\\b"                , @"la"},        // la French or La Spanish.\n            {@"\\bL([eo])\\b"           , @"l$1"},       // lo Italian; le French.\n            {@"\\bVan(?=\\s+\\w)"        , @"van"},       // van German or forename Van.\n            {@"\\bVon\\b"               , @"von"}        // von Dutch/Flemish\n        };\n\n    static string[] _conjunctions = { "Y", "E", "I" };\n\n    static string _romanRegex = @"\\b((?:[Xx]{1,3}|[Xx][Ll]|[Ll][Xx]{0,3})?(?:[Ii]{1,3}|[Ii][VvXx]|[Vv][Ii]{0,3})?)\\b";\n\n    /// &lt;summary&gt;\n    /// Case a name field into its appropriate case format \n    /// e.g. Smith, de la Cruz, Mary-Jane,  O\'Brien, McTaggart\n    /// &lt;/summary&gt;\n    /// &lt;param name="nameString"&gt;&lt;/param&gt;\n    /// &lt;returns&gt;&lt;/returns&gt;\n    public static string NameCase(string nameString)\n    {\n        // Capitalize\n        nameString = Capitalize(nameString);\n        nameString = UpdateIrish(nameString);\n\n        // Fixes for "son (daughter) of" etc\n        foreach (var replacement in _replacements.Keys)\n        {\n            if (Regex.IsMatch(nameString, replacement))\n            {\n                Regex rgx = new Regex(replacement);\n                nameString = rgx.Replace(nameString, _replacements[replacement]);\n            }                    \n        }\n\n        nameString = UpdateRoman(nameString);\n        nameString = FixConjunction(nameString);\n\n        return nameString;\n    }\n\n    /// &lt;summary&gt;\n    /// Capitalize first letters.\n    /// &lt;/summary&gt;\n    /// &lt;param name="nameString"&gt;&lt;/param&gt;\n    /// &lt;returns&gt;&lt;/returns&gt;\n    private static string Capitalize(string nameString)\n    {\n        nameString = nameString.ToLower();\n        nameString = Regex.Replace(nameString, @"\\b\\w", x =&gt; x.ToString().ToUpper());\n        nameString = Regex.Replace(nameString, @"\'\\w\\b", x =&gt; x.ToString().ToLower()); // Lowercase \'s\n        return nameString;\n    }\n\n    /// &lt;summary&gt;\n    /// Update for Irish names.\n    /// &lt;/summary&gt;\n    /// &lt;param name="nameString"&gt;&lt;/param&gt;\n    /// &lt;returns&gt;&lt;/returns&gt;\n    private static string UpdateIrish(string nameString)\n    {\n        if(Regex.IsMatch(nameString, @".*?\\bMac[A-Za-z^aciozj]{2,}\\b") || Regex.IsMatch(nameString, @".*?\\bMc"))\n        {\n            nameString = UpdateMac(nameString);\n        }            \n        return nameString;\n    }\n\n    /// &lt;summary&gt;\n    /// Updates irish Mac &amp; Mc.\n    /// &lt;/summary&gt;\n    /// &lt;param name="nameString"&gt;&lt;/param&gt;\n    /// &lt;returns&gt;&lt;/returns&gt;\n    private static string UpdateMac(string nameString)\n    {\n        MatchCollection matches = Regex.Matches(nameString, @"\\b(Ma?c)([A-Za-z]+)");\n        if(matches.Count == 1 &amp;&amp; matches[0].Groups.Count == 3)\n        {\n            string replacement = matches[0].Groups[1].Value;\n            replacement += matches[0].Groups[2].Value.Substring(0, 1).ToUpper();\n            replacement += matches[0].Groups[2].Value.Substring(1);\n            nameString = nameString.Replace(matches[0].Groups[0].Value, replacement);\n\n            // Now fix "Mac" exceptions\n            foreach (var exception in _exceptions.Keys)\n            {\n                nameString = Regex.Replace(nameString, exception, _exceptions[exception]);\n            }\n        }\n        return nameString;\n    }\n\n    /// &lt;summary&gt;\n    /// Fix roman numeral names.\n    /// &lt;/summary&gt;\n    /// &lt;param name="nameString"&gt;&lt;/param&gt;\n    /// &lt;returns&gt;&lt;/returns&gt;\n    private static string UpdateRoman(string nameString)\n    {\n        MatchCollection matches = Regex.Matches(nameString, _romanRegex);\n        if (matches.Count &gt; 1)\n        {\n            foreach(Match match in matches)\n            {\n                if(!string.IsNullOrEmpty(match.Value))\n                {\n                    nameString = Regex.Replace(nameString, match.Value, x =&gt; x.ToString().ToUpper());\n                }\n            }\n        }\n        return nameString;\n    }\n\n    /// &lt;summary&gt;\n    /// Fix Spanish conjunctions.\n    /// &lt;/summary&gt;\n    /// &lt;param name=""&gt;&lt;/param&gt;\n    /// &lt;returns&gt;&lt;/returns&gt;\n    private static string FixConjunction(string nameString)\n    {            \n        foreach (var conjunction in _conjunctions)\n        {\n            nameString = Regex.Replace(nameString, @"\\b" + conjunction + @"\\b", x =&gt; x.ToString().ToLower());\n        }\n        return nameString;\n    }\n}\n</code></pre>\n\n<p>Usage</p>\n\n<pre class="lang-cs prettyprint-override"><code>string name_cased = CIQNameCase.NameCase("McCarthy");\n</code></pre>\n\n<p>This is my test method, everything seems to pass OK:</p>\n\n<pre class="lang-cs prettyprint-override"><code>[TestMethod]\npublic void Test_NameCase_1()\n{\n    string[] names = {\n        "Keith", "Yuri\'s", "Leigh-Williams", "McCarthy",\n        // Mac exceptions\n        "Machin", "Machlin", "Machar",\n        "Mackle", "Macklin", "Mackie",\n        "Macquarie", "Machado", "Macevicius",\n        "Maciulis", "Macias", "MacMurdo",\n        // General\n        "O\'Callaghan", "St. John", "von Streit",\n        "van Dyke", "Van", "ap Llwyd Dafydd",\n        "al Fahd", "Al",\n        "el Grecco",\n        "ben Gurion", "Ben",\n        "da Vinci",\n        "di Caprio", "du Pont", "de Legate",\n        "del Crond", "der Sind", "van der Post", "van den Thillart",\n        "von Trapp", "la Poisson", "le Figaro",\n        "Mack Knife", "Dougal MacDonald",\n        "Ruiz y Picasso", "Dato e Iradier", "Mas i Gavarró",\n        // Roman numerals\n        "Henry VIII", "Louis III", "Louis XIV",\n        "Charles II", "Fred XLIX", "Yusof bin Ishak",\n    };\n\n    foreach(string name in names)\n    {\n        string name_upper = name.ToUpper();\n        string name_cased = CIQNameCase.NameCase(name_upper);\n        Console.WriteLine(string.Format("name: {0} -&gt; {1}  -&gt; {2}", name, name_upper, name_cased));\n        Assert.IsTrue(name == name_cased);\n    }\n\n}\n</code></pre>\n'}, {'answer_id': 45872439, 'author': 'Klyphtn', 'author_id': 4705498, 'author_profile': 'https://Stackoverflow.com/users/4705498', 'pm_score': 0, 'selected': False, 'text': '<p>A lot of good answers here. Mine is pretty simple and only takes into account the names we have in our organization. You can expand it as you wish. This is not a perfect solution and will change vancouver to VanCouver, which is wrong. So tweak it if you use it.</p>\n\n<p>Here was my solution in C#. This hard-codes the names into the program but with a little work you could keep a text file outside of the program and read in the name exceptions (i.e. Van, Mc, Mac) and loop through them. </p>\n\n<pre><code>public static String toProperName(String name)\n{\n    if (name != null)\n    {\n        if (name.Length &gt;= 2 &amp;&amp; name.ToLower().Substring(0, 2) == "mc")  // Changes mcdonald to "McDonald"\n            return "Mc" + Regex.Replace(name.ToLower().Substring(2), @"\\b[a-z]", m =&gt; m.Value.ToUpper());\n\n        if (name.Length &gt;= 3 &amp;&amp; name.ToLower().Substring(0, 3) == "van")  // Changes vanwinkle to "VanWinkle"\n            return "Van" + Regex.Replace(name.ToLower().Substring(3), @"\\b[a-z]", m =&gt; m.Value.ToUpper());\n\n        return Regex.Replace(name.ToLower(), @"\\b[a-z]", m =&gt; m.Value.ToUpper());  // Changes to title case but also fixes \n                                                                                   // appostrophes like O\'HARE or o\'hare to O\'Hare\n    }\n\n    return "";\n}\n</code></pre>\n'}, {'answer_id': 47704958, 'author': 'Michael Pinkard', 'author_id': 5712417, 'author_profile': 'https://Stackoverflow.com/users/5712417', 'pm_score': 1, 'selected': False, 'text': '<p>I know this thread has been open for awhile, but as I was doing research for this problem I came across this nifty site, which allows you to paste in names to be capitalized quite quickly: <a href="https://dialect.ca/code/name-case/" rel="nofollow noreferrer">https://dialect.ca/code/name-case/</a>. I wanted to include it here for reference for others doing similar research/projects.</p>\n\n<p>They release the algorithm they have written in php at this link: <a href="https://dialect.ca/code/name-case/name_case.phps" rel="nofollow noreferrer">https://dialect.ca/code/name-case/name_case.phps</a></p>\n\n<p>A preliminary test and reading of their code suggests they have been quite thorough.</p>\n'}]
['https://Stackoverflow.com/questions/32149', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/3203/']