// // Titlecasing: // ----------- // Titlecasing refers to a casing practice wherein the first letter of a word is an uppercase letter // and the rest of the letters are lowercase. The choice of which words to titlecase in headings // and titles is dependent on language and local conventions. For example, "The Merry Wives of Windor" // is the appropriate titlecasing of that play's name in English, with the word "of" not titlecased. // In German, however, the title is "Die lustigen Weiber von Windsor," and both "lustigen" and "von" // are not titlecased. In French even fewer words are titlecased: "Les joyeuses commeres de Windsor." // // Moreover, the determination of what actually constitutes a word is language dependent, and this can // influence which letter or letters of a "word" are uppercased when titlecasing strings. For example // "l'arbre" is considered two words in French, whereas "can't" is considered one word in English. // public unsafe String ToTitleCase(String str) { if (str == null) { throw new ArgumentNullException(nameof(str)); } Contract.EndContractBlock(); if (str.Length == 0) { return(str); } StringBuilder result = new StringBuilder(); string lowercaseData = null; // Store if the current culture is Dutch (special case) bool isDutchCulture = CultureName.StartsWith("nl-", StringComparison.OrdinalIgnoreCase); for (int i = 0; i < str.Length; i++) { UnicodeCategory charType; int charLen; charType = CharUnicodeInfo.InternalGetUnicodeCategory(str, i, out charLen); if (Char.CheckLetter(charType)) { // Special case to check for Dutch specific titlecasing with "IJ" characters // at the beginning of a word if (isDutchCulture && i < str.Length - 1 && (str[i] == 'i' || str[i] == 'I') && (str[i + 1] == 'j' || str[i + 1] == 'J')) { result.Append("IJ"); i += 2; } else { // Do the titlecasing for the first character of the word. i = AddTitlecaseLetter(ref result, ref str, i, charLen) + 1; } // // Convert the characters until the end of the this word // to lowercase. // int lowercaseStart = i; // // Use hasLowerCase flag to prevent from lowercasing acronyms (like "URT", "USA", etc) // This is in line with Word 2000 behavior of titlecasing. // bool hasLowerCase = (charType == UnicodeCategory.LowercaseLetter); // Use a loop to find all of the other letters following this letter. while (i < str.Length) { charType = CharUnicodeInfo.InternalGetUnicodeCategory(str, i, out charLen); if (IsLetterCategory(charType)) { if (charType == UnicodeCategory.LowercaseLetter) { hasLowerCase = true; } i += charLen; } else if (str[i] == '\'') { i++; if (hasLowerCase) { if (lowercaseData == null) { lowercaseData = this.ToLower(str); } result.Append(lowercaseData, lowercaseStart, i - lowercaseStart); } else { result.Append(str, lowercaseStart, i - lowercaseStart); } lowercaseStart = i; hasLowerCase = true; } else if (!IsWordSeparator(charType)) { // This category is considered to be part of the word. // This is any category that is marked as false in wordSeprator array. i += charLen; } else { // A word separator. Break out of the loop. break; } } int count = i - lowercaseStart; if (count > 0) { if (hasLowerCase) { if (lowercaseData == null) { lowercaseData = this.ToLower(str); } result.Append(lowercaseData, lowercaseStart, count); } else { result.Append(str, lowercaseStart, count); } } if (i < str.Length) { // not a letter, just append it i = AddNonLetter(ref result, ref str, i, charLen); } } else { // not a letter, just append it i = AddNonLetter(ref result, ref str, i, charLen); } } return(result.ToString()); }
// // Titlecasing: // ----------- // Titlecasing refers to a casing practice wherein the first letter of a word is an uppercase letter // and the rest of the letters are lowercase. The choice of which words to titlecase in headings // and titles is dependent on language and local conventions. For example, "The Merry Wives of Windor" // is the appropriate titlecasing of that play's name in English, with the word "of" not titlecased. // In German, however, the title is "Die lustigen Weiber von Windsor," and both "lustigen" and "von" // are not titlecased. In French even fewer words are titlecased: "Les joyeuses commeres de Windsor." // // Moreover, the determination of what actually constitutes a word is language dependent, and this can // influence which letter or letters of a "word" are uppercased when titlecasing strings. For example // "l'arbre" is considered two words in French, whereas "can't" is considered one word in English. // // // Differences between UNICODE 5.0 and the .NET Framework ( #if !FEATURE_CORECLR public unsafe String ToTitleCase(String str) { if (str == null) { throw new ArgumentNullException("str"); } Contract.EndContractBlock(); if (str.Length == 0) { return(str); } StringBuilder result = new StringBuilder(); String lowercaseData = null; for (int i = 0; i < str.Length; i++) { UnicodeCategory charType; int charLen; charType = CharUnicodeInfo.InternalGetUnicodeCategory(str, i, out charLen); if (Char.CheckLetter(charType)) { // Do the titlecasing for the first character of the word. i = AddTitlecaseLetter(ref result, ref str, i, charLen) + 1; // // Convert the characters until the end of the this word // to lowercase. // int lowercaseStart = i; // // Use hasLowerCase flag to prevent from lowercasing acronyms (like "URT", "USA", etc) // This is in line with Word 2000 behavior of titlecasing. // bool hasLowerCase = (charType == UnicodeCategory.LowercaseLetter); // Use a loop to find all of the other letters following this letter. while (i < str.Length) { charType = CharUnicodeInfo.InternalGetUnicodeCategory(str, i, out charLen); if (IsLetterCategory(charType)) { if (charType == UnicodeCategory.LowercaseLetter) { hasLowerCase = true; } i += charLen; } else if (str[i] == '\'') { // i++; if (hasLowerCase) { if (lowercaseData == null) { lowercaseData = this.ToLower(str); } result.Append(lowercaseData, lowercaseStart, i - lowercaseStart); } else { result.Append(str, lowercaseStart, i - lowercaseStart); } lowercaseStart = i; hasLowerCase = true; } else if (!IsWordSeparator(charType)) { // This category is considered to be part of the word. // This is any category that is marked as false in wordSeprator array. i += charLen; } else { // A word separator. Break out of the loop. break; } } int count = i - lowercaseStart; if (count > 0) { if (hasLowerCase) { if (lowercaseData == null) { lowercaseData = this.ToLower(str); } result.Append(lowercaseData, lowercaseStart, count); } else { result.Append(str, lowercaseStart, count); } } if (i < str.Length) { // not a letter, just append it i = AddNonLetter(ref result, ref str, i, charLen); } } else { // not a letter, just append it i = AddNonLetter(ref result, ref str, i, charLen); } } return(result.ToString()); }
public unsafe String ToTitleCase(String str) { if (str == null) { throw new ArgumentNullException("str"); } int len = str.Length; if (len == 0) { return(str); } int i; StringBuilder result = new StringBuilder(); String lowercaseData = null; for (i = 0; i < len; i++) { UnicodeCategory charType; int charLen; charType = CharUnicodeInfo.InternalGetUnicodeCategory(str, i, out charLen); if (Char.CheckLetter(charType)) { // Do the uppercasing for the first character of the word. // There are titlecase characters that need to be special treated. if (charLen == 1) { result.Append(nativeGetTitleCaseChar(m_pNativeTextInfo, str[i])); } else { // // ASSUMPTION: There is no titlecase char in the surrogate. // char resultHighSurrogate; char resultLowSurrogate; ChangeCaseSurrogate(str[i], str[i + 1], out resultHighSurrogate, out resultLowSurrogate, true); result.Append(resultHighSurrogate); result.Append(resultLowSurrogate); } i += charLen; // // Convert the characters until the end of the this word // to lowercase. // int lowercaseStart = i; // // Use hasLowerCase flag to prevent from lowercasing acronyms (like "URT", "USA", etc) // This is in line with Word 2000 behavior of titilecasing. // bool hasLowerCase = (charType == UnicodeCategory.LowercaseLetter); // Use a loop to find all of the other letters following this letter. while (i < len) { charType = CharUnicodeInfo.InternalGetUnicodeCategory(str, i, out charLen); if (IsLetterCategory(charType)) { if (charType == UnicodeCategory.LowercaseLetter) { hasLowerCase = true; } i += charLen; } else if (str[i] == '\'') { // Special case for APOSTROPHE. It should be considered part of the word. E.g. "can't". i++; if (hasLowerCase) { if (lowercaseData == null) { lowercaseData = this.ToLower(str); } result.Append(lowercaseData, lowercaseStart, i - lowercaseStart); } else { result.Append(str, lowercaseStart, i - lowercaseStart); } lowercaseStart = i; hasLowerCase = true; } else if (!IsWordSeparator(charType)) { // This category is considered to be part of the word. // This is any category that is marked as false in wordSeprator array. i += charLen; } else { // A word separator. Break out of the loop. break; } } int count = i - lowercaseStart; if (count > 0) { if (hasLowerCase) { if (lowercaseData == null) { lowercaseData = this.ToLower(str); } result.Append(lowercaseData, lowercaseStart, count); } else { result.Append(str, lowercaseStart, count); } } if (i < len) { // Add the non-letter character. if (charLen == 1) { result.Append(str[i]); } else { // Surrogate. result.Append(str[i++]); result.Append(str[i]); } } } else { // // Not a letter, just append them. // if (charLen == 1) { result.Append(str[i]); } else { // Surrogate. result.Append(str[i++]); result.Append(str[i]); } } } return(result.ToString()); }