diff --git a/release_notes.md b/release_notes.md index bdb42f1ae..1853f41ef 100644 --- a/release_notes.md +++ b/release_notes.md @@ -1,4 +1,5 @@ ###In Development + - [#341](https://github.com/MehdiK/Humanizer/pull/341): Added logic to properly treat underscores, dashes and spaces. [Commits](https://github.com/MehdiK/Humanizer/compare/v1.29.0...master) diff --git a/src/Humanizer.Tests/StringHumanizeTests.cs b/src/Humanizer.Tests/StringHumanizeTests.cs index 0af0ca213..800decee7 100644 --- a/src/Humanizer.Tests/StringHumanizeTests.cs +++ b/src/Humanizer.Tests/StringHumanizeTests.cs @@ -11,6 +11,7 @@ public class StringHumanizeTests [InlineData("10IsInTheBegining", "10 is in the begining")] [InlineData("NumberIsAtTheEnd100", "Number is at the end 100")] [InlineData("XIsFirstWordInTheSentence", "X is first word in the sentence")] + [InlineData("XIsFirstWordInTheSentence ThenThereIsASpace", "X is first word in the sentence then there is a space")] public void CanHumanizeStringInPascalCase(string input, string expectedResult) { Assert.Equal(expectedResult, input.Humanize()); @@ -19,6 +20,14 @@ public void CanHumanizeStringInPascalCase(string input, string expectedResult) [Theory] [InlineData("Underscored_input_string_is_turned_into_sentence", "Underscored input string is turned into sentence")] [InlineData("Underscored_input_String_is_turned_INTO_sentence", "Underscored input String is turned INTO sentence")] + [InlineData("TEST 1 - THIS IS A TEST", "TEST 1 THIS IS A TEST")] + [InlineData("TEST 1 -THIS IS A TEST", "TEST 1 THIS IS A TEST")] + [InlineData("TEST 1- THIS IS A TEST", "TEST 1 THIS IS A TEST")] + [InlineData("TEST 1_ THIS IS A TEST", "TEST 1 THIS IS A TEST")] + [InlineData("TEST 1 _THIS IS A TEST", "TEST 1 THIS IS A TEST")] + [InlineData("TEST 1 _ THIS IS A TEST", "TEST 1 THIS IS A TEST")] + [InlineData("TEST 1 - THIS_IS_A_TEST", "TEST 1 THIS IS A TEST")] + [InlineData("TEST 1 - THIS is A Test", "TEST 1 THIS is A test")] public void CanHumanizeStringWithUnderscores(string input, string expectedReseult) { Assert.Equal(expectedReseult, input.Humanize()); @@ -28,6 +37,7 @@ public void CanHumanizeStringWithUnderscores(string input, string expectedReseul [InlineData("HTML", "HTML")] [InlineData("TheHTMLLanguage", "The HTML language")] [InlineData("HTMLIsTheLanguage", "HTML is the language")] + [InlineData("TheLanguage IsHTML", "The language is HTML")] [InlineData("TheLanguageIsHTML", "The language is HTML")] [InlineData("HTML5", "HTML 5")] [InlineData("1HTML", "1 HTML")] diff --git a/src/Humanizer/StringHumanizeExtensions.cs b/src/Humanizer/StringHumanizeExtensions.cs index ed597604c..cf60c2e58 100644 --- a/src/Humanizer/StringHumanizeExtensions.cs +++ b/src/Humanizer/StringHumanizeExtensions.cs @@ -24,16 +24,18 @@ static string FromPascalCase(string input) (?# acronym to number) (?<=[A-Z])(?=[0-9])| (?# acronym to word) -(?<=[A-Z])(?=[A-Z][a-z]) +(?<=[A-Z])(?=[A-Z][a-z])| +(?# words/acronyms/numbers separated by space) +(?<=[^\s])(?=[\s]) ", RegexOptions.IgnorePatternWhitespace); var result = pascalCaseWordBoundaryRegex .Split(input) .Select(word => - word.ToCharArray().All(Char.IsUpper) && word.Length > 1 + word.Trim().ToCharArray().All(Char.IsUpper) && word.Length > 1 ? word : word.ToLower()) - .Aggregate((res, word) => res + " " + word); + .Aggregate((res, word) => res + " " + word.Trim()); result = Char.ToUpper(result[0]) + result.Substring(1, result.Length - 1); @@ -51,6 +53,12 @@ public static string Humanize(this string input) if (input.ToCharArray().All(Char.IsUpper)) return input; + // if input contains a dash or underscore which preceeds or follows a space (or both, i.g. free-standing) + // remove the dash/underscore and run it through FromPascalCase + Regex r = new Regex(@"[\s]{1}[-_]|[-_][\s]{1}", RegexOptions.IgnoreCase); + if (r.IsMatch(input)) + return FromPascalCase(FromUnderscoreDashSeparatedWords(input)); + if (input.Contains("_") || input.Contains("-")) return FromUnderscoreDashSeparatedWords(input);