/// <summary> /// Get the resolved JSON property name for the given property name. /// </summary> /// <param name="propertyName">The property name.</param> /// <returns>The JSON property name.</returns> public new string GetResolvedPropertyName(string propertyName) { if (propertyName == null) { throw new ArgumentNullException("propertyName"); } // split the words up IEnumerable <string> words = new[] { propertyName }; if (WordSplitOptions.HasFlag(WordSplitOptions.SplitUnderscore)) { words = words.SelectMany(SplitUnderscore); } if (WordSplitOptions.HasFlag(WordSplitOptions.SplitCamelCase)) { words = words.SelectMany(SplitCamelCase); } if (WordSplitOptions.HasFlag(WordSplitOptions.SplitAcronyms)) { words = words.SelectMany(SplitAcronyms); } // apply capitalizations switch (CapitalizationOptions) { case CapitalizationOptions.PreserveOriginal: break; case CapitalizationOptions.AllLowercase: words = words.Select(w => w.ToLower()); break; case CapitalizationOptions.AllUppercase: words = words.Select(w => w.ToUpper()); break; case CapitalizationOptions.CamelCase: words = words.Select((w, i) => i == 0 ? w.ToLower() : char.ToUpper(w[0]) + w.Substring(1).ToLower()); break; case CapitalizationOptions.PascalCase: words = words.Select(w => char.ToUpper(w[0]) + w.Substring(1).ToLower()); break; case CapitalizationOptions.CamelCaseWithAcronyms: words = words.Select((w, i) => w.ToUpper() == w ? w : i == 0 ? w.ToLower() : char.ToUpper(w[0]) + w.Substring(1).ToLower()); break; case CapitalizationOptions.PascalCaseWithAcronyms: words = words.Select(w => w.ToUpper() == w ? w : char.ToUpper(w[0]) + w.Substring(1).ToLower()); break; } // join the words return(string.Join(WordDelimiter ?? string.Empty, words)); }
/// <summary> /// Returns all words in given string. A 'word' is considered to be any sequence of letters or digits. /// </summary> public static IEnumerable <string> GetWords(this string source, WordSplitOptions options = WordSplitOptions.None) { if (source == null) { throw new ArgumentNullException(nameof(source)); } foreach (var(start, end) in GetWordBoundaries(source, options: options)) { yield return(source.Substring(start, end - start)); } }
private static void VerifyGetResolvedPropertyName(WordSplitOptions wordSplitOptions, CapitalizationOptions capitalizationOptions, string wordDelimiter, string input, string expected) { // ARRANGE var resolver = new StandardContractResolver { WordSplitOptions = wordSplitOptions, CapitalizationOptions = capitalizationOptions, WordDelimiter = wordDelimiter }; // ACT string actual = resolver.GetResolvedPropertyName(input); // ASSERT Assert.AreEqual(expected, actual); }
/// <summary> /// Returns `start` (inclusive) and `end` (exclusive) indexes of all words in given string. A 'word' is considered to be any sequence of letters or digits. /// </summary> public static IEnumerable <(int start, int end)> GetWordBoundaries(this string source, WordSplitOptions options = WordSplitOptions.None) { if (source == null) { throw new ArgumentNullException(nameof(source)); } var splitOnUpperLetter = options.HasFlag(WordSplitOptions.SplitOnUpperLetter); // todo: I'm pretty confident that this can fail due to some unicode shenanigans var startIndex = -1; for (var i = 0; i < source.Length; i++) { var isLetterOrDigit = char.IsLetterOrDigit(source, i); if (startIndex != -1) { if (!isLetterOrDigit) { yield return(startIndex, i); startIndex = -1; } else if (splitOnUpperLetter) { if (char.IsUpper(source, i) && (i == 0 || !char.IsUpper(source, i - 1))) { yield return(startIndex, i); startIndex = i; } } } else { if (isLetterOrDigit) { startIndex = i; } } } if (startIndex != -1) { yield return(startIndex, source.Length); } }