// // 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)); } 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 = 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 = 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()); }
/// <summary> /// Compares this CultureTextViewModel instance with another instance to determine the sort /// order in the editor view. /// </summary> /// <param name="other"></param> /// <returns></returns> public int CompareTo(CultureTextViewModel other) { string otherName = other.CultureName; if (string.Compare(CultureName, otherName, StringComparison.InvariantCultureIgnoreCase) == 0) { //System.Diagnostics.Debug.WriteLine(CultureName + " = " + otherName + " (1)"); return(0); // Exact match } if (CultureName.Length >= 2 && otherName.Length >= 2) { // Prefer primary culture (with or without region; if set) if (!string.IsNullOrEmpty(TextKeyVM.MainWindowVM.PrimaryCulture)) { // tP: thisPrimary // oP: otherPrimary // oPR: otherPrimaryRelated // // !tPR tPR // !tP tP !tP tP // -------------------------- // !oPR !oP | cont. xxx | -1 -1 | // oP | xxx xxx | xxx xxx | // -------------------------- // oPR !oP | 1 xxx | cont. -1 | // oP | 1 xxx | 1 xxx | // -------------------------- bool thisPrimary = string.Compare(CultureName, TextKeyVM.MainWindowVM.PrimaryCulture, StringComparison.InvariantCultureIgnoreCase) == 0; bool thisPrimaryRelated = CultureName.StartsWith(TextKeyVM.MainWindowVM.PrimaryCulture.Substring(0, 2)); bool otherPrimary = string.Compare(otherName, TextKeyVM.MainWindowVM.PrimaryCulture, StringComparison.InvariantCultureIgnoreCase) == 0; bool otherPrimaryRelated = otherName.StartsWith(TextKeyVM.MainWindowVM.PrimaryCulture.Substring(0, 2)); if (thisPrimary || thisPrimaryRelated && !otherPrimaryRelated) { //System.Diagnostics.Debug.WriteLine(CultureName + " < " + otherName + " (2)"); return(-1); } if (otherPrimary || otherPrimaryRelated && !thisPrimaryRelated) { //System.Diagnostics.Debug.WriteLine(CultureName + " > " + otherName + " (2)"); return(1); } } if (string.Compare(CultureName.Substring(0, 2), otherName.Substring(0, 2), StringComparison.InvariantCultureIgnoreCase) == 0) { // Same language, prefer shorter names (without region) if (CultureName.Length != otherName.Length) { int i = CultureName.Length - otherName.Length; //if (i < 0) // System.Diagnostics.Debug.WriteLine(CultureName + " < " + otherName + " (3)"); //else if (i > 0) // System.Diagnostics.Debug.WriteLine(CultureName + " > " + otherName + " (3)"); //else // System.Diagnostics.Debug.WriteLine(CultureName + " = " + otherName + " (3)"); return(i); // If this.length < other.length, then the result is negative and this comes before other } } } return(string.Compare(CultureName, otherName, StringComparison.InvariantCultureIgnoreCase)); }