Capitalizing words in a string using c#

I need to take a string, and capitalize words in it. Certain words ("in", "at", etc.), are not capitalized and are changed to lower case if encountered. The first word should always be capitalized. Last names like "McFly" are not in the current scope so the same rule will apply to them - only first letter capitalized.

For example: "of mice and men By CNN" should be changed to "Of Mice and Men by CNN". (Therefore ToTitleString won't work here)

I'm wondering what would be the best way to do that. What I thought of is to split the string by spaces, and go over each word, changing it if necessary, and concatenating it to the previous word, and so on. It seems pretty naive and I was wondering if there's a better way to do it, using .Net 3.5.

Answers


Depending on how often you plan on doing the capitalization I'd go with the naive approach. You could possibly do it with a regular expression, but the fact that you don't want certain words capitalized makes that a little trickier.

Edit:

You can do it with two passes using regexes

var result = Regex.Replace("of mice and men isn't By CNN", @"\b(\w)", m => m.Value.ToUpper());
result = Regex.Replace(result, @"(\s(of|in|by|and)|\'[st])\b", m => m.Value.ToLower(), RegexOptions.IgnoreCase);

This outputs Of Mice and Men Isn't by CNN.

The first expression capitalizes every letter on a word boundary and the second one downcases any words matching the list that are surrounded by whitespace.

The downsides to this approach is that you're using regexs (now you have two problems) and you'll need to keep that list of excluded words up to date. My regex-fu isn't good enough to be able to do it in one expression, but it might be possible.


Here is answer How to Capitalize names using C#

CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
TextInfo textInfo = cultureInfo.TextInfo;

Console.WriteLine(textInfo.ToTitleCase(title));
Console.WriteLine(textInfo.ToLower(title));
Console.WriteLine(textInfo.ToUpper(title));

Use

Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase("of mice and men By CNN");

to convert to proper case and then you can loop through the keywords as you have mentioned.


Why not use ToTitleCase() first and then keep a list of applicable words and Replace back to the all-lower-case version of those applicable words (provided that list is small). The list of applicable words could be kept in a dictionary and looped through pretty efficiently, replacing with the .ToLower() equivalent.


Try something like this:

public static string TitleCase(string input, params string[] dontCapitalize) {
   var split = input.Split(' ');
   for(int i = 0; i < split.Length; i++)
        split[i] = i == 0 
          ? CapitalizeWord(split[i]) 
          : dontCapitalize.Contains(split[i])
             ? split[i]
             : CapitalizeWord(split[i]);
   return string.Join(" ", split);
}
public static string CapitalizeWord(string word)
{
    return char.ToUpper(word[0]) + word.Substring(1);
}

You can then later update the CapitalizeWord method if you need to handle complex surnames. Add those methods to a class and use it like this:

SomeClass.TitleCase("a test is a sentence", "is", "a"); // returns "A Test is a Sentence"

You can have a Dictionary having the words you would like to ignore, split the sentence in phrases (.split(' ')) and for each phrase, check if the phrase exists in the dictionary, if it does not, capitalize the first character and then, add the string to a string buffer. If the phrase you are currently processing is in the dictionary, simply add it to the string buffer.


A slight improvement on jonnii's answer:

var result = Regex.Replace(s.Trim(), @"\b(\w)", m => m.Value.ToUpper());
        result = Regex.Replace(result, @"\s(of|in|by|and)\s", m => m.Value.ToLower(), RegexOptions.IgnoreCase);
        result = result.Replace("'S", "'s");

You should create your own function like you're describing.


A non-clever approach that handles the simple case:

var s = "of mice and men By CNN";
var sa = s.Split(' ');
for (var i = 0; i < sa.Length; i++)
    sa[i] = sa[i].Substring(0, 1).ToUpper() + sa[i].Substring(1);
var sout = string.Join(" ", sa);
Console.WriteLine(sout);

The easiest obvious solution (for English sentences) would be to:

  • "sentence".Split(" ") the sentence on space characters
  • Loop through each item
  • Capitalize the first letter of each item - item[i][0].ToUpper(),
  • Remerge back into a string joined on a space.
  • Repeat this process with "." and "," using that new string.

Need Your Help

Is it possible to store a SQL Server table on the user's local hard drive?

php sql sql-server sql-server-2008

I have a database in a state own ms sql server. Writing user information in

WPF: TreeView height

c# wpf xaml treeview

I'm using a TreeView in WPF that has an explicit height set. The vertical scrollbar is cut off at the bottom (independent of whether items are bound/shown or not; I've enabled the scrollbar to be a...