How to capitalize names
Basically if I want to transform a name from
steph开发者_运维知识库en smith
to
Stephen Smith
I can easily do it with come CSS on the page, but ideally I would like to catch it earlier on and change it when it comes out of the database. How can I get C# to capitalise a string?
Is there a function for this?
You can do this using the ToTitleCase
method of the System.Globalization.TextInfo class:
CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
TextInfo textInfo = cultureInfo.TextInfo;
Console.WriteLine(textInfo.ToTitleCase(title));
Console.WriteLine(textInfo.ToLower(title));
Console.WriteLine(textInfo.ToUpper(title));
Names are tricky. The simple rules of First Letters do not apply. The only sensible approach here is to ask your users how they want it. Anything else can cause offence.
If my name is MacPhearson, ODowel, or just simply marc, Marc or even mArC - then frankly: leave it alone. Trust the user to get it right. This gets even more tricky as you go between cultures.
This is an extension method on the string class that capitalizes a single word. You can use it alongside a str.Split()
and str.Join
to capitalize every word of the str
string. You can add checks for empty or one character length strings.
public static string Capitalize(this string word)
{
return word.Substring(0, 1).ToUpper() + word.Substring(1).ToLower();
}
Note that the process will most likely be slow if you have many, many strings to change case...
string str = "to title case";
Char[] ca = str.ToCharArray();
foreach(Match m in Regex.Matches(str, @"\b[a-z]"))
{
ca[m.Index] = Char.ToUpper(ca[m.Index]);
}
Console.WriteLine(new string(ca));
Or you could also use a custom evaluator to change the case like this:
string str = "to title case";
Console.WriteLine(Regex.Replace(str, @"\b[a-z]", delegate (Match m)
{
return m.Value.ToUpper();
}
));
Note that in my test with 1,000,000 iterations the first method was only 0.48 seconds faster than the one with the evaluator (the first one took 6.88 seconds and the latter 7.36 seconds to complete the 1,000,000 iterations) so I wouldn't take speed into account to choose either...
No, there isn't. Providing you know the string you are handling is a name (or, better to say, a sequence of human names separated by spaces) you should be able to code it yourself within one for
cycle and using Char.ToUpper
. However, there a culture-specific cases like Arabian words "bin", "al", etc. used in names, which shall not be capitalized (providing a Latin transcription is used). The same holds for "von" or "van" in Western languages.
Please note that the TextInfo.ToTitleCase
serves a different purpose — it's not intended to capitalize first letters of human names, but to provide proper casing of titles (like headlines of news articles to be clear).
Although the current implementation in .NET can easily serve the requested purpose, I'd avoid doing so. The reason is the implementation may change significantly in the future and hence it's safer to make a custom implementation for human names. Moreover, I doubt the method is really usable for title-casing of strings with respect to the given culture. For example, in Czech ("cs-CZ"
) the proper title-case should capitalize just the first letter of the first word only.
A slight extension on the answer offered by Pedro:
Regex.Replace(Name, @"(?:(M|m)(c)|(\b))([a-z])", delegate(Match m) {
return String.Concat(m.Groups[1].Value.ToUpper(), m.Groups[2].Value, m.Groups[3].Value, m.Groups[4].Value.ToUpper());
});
This will correctly capitalize McNames in addition to title case. For example,
"simon mcguinnis" → "Simon McGuinnis"
The first non-capture group will match any word-break character OR "Mc" / "mc".
If it matches a word-break, then groups 1 and 2 are empty and group 3 contains that character.
If it matches "Mc" or "mc" the groups 1 and 2 contain "m" and "c" and group 3 is empty.
Group 1 (the "m" or "M") is capitalized.
Group 2 (the "c") remains un-altered.
Group 3 (the break character) remains un-altered.
Group 4 (the first letter of the next word) is capitalized.
All four groups, empty or otherwise, are concatenated to generate the return string.
I use a single line:
string.Join(" ", str.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(c => c.Substring(0, 1).ToUpper() + c.Substring(1).ToLower()));
This works for me with surnames that have a ' character in them.
if (Surname.Contains("'"))
{
String[] Names = Surname.Split('\'').ToArray();
Surname = textInfo.ToTitleCase(Names[0].ToString());
Surname += "''";
Surname += textInfo.ToTitleCase(Names[1].ToString());
}
精彩评论