From a19323a9b5c79c2a12273bfba5dcd0d49835763c Mon Sep 17 00:00:00 2001 From: Cath Fawcet Date: Sat, 29 May 2021 14:46:05 +1200 Subject: [PATCH] Fixes #1006: conjunctions etc lower case in Title Case --- src/Humanizer.Tests.Shared/InflectorTests.cs | 6 ++-- .../StringHumanizeTests.cs | 1 + .../TransformersTests.cs | 2 +- src/Humanizer/Transformer/ToTitleCase.cs | 29 ++++++++++++++++--- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/Humanizer.Tests.Shared/InflectorTests.cs b/src/Humanizer.Tests.Shared/InflectorTests.cs index c57b66cda..41ed9aa87 100644 --- a/src/Humanizer.Tests.Shared/InflectorTests.cs +++ b/src/Humanizer.Tests.Shared/InflectorTests.cs @@ -75,9 +75,9 @@ public void SingularizeSkipSimpleWords(string singular, string plural) [InlineData("some title", "Some Title")] [InlineData("some-title", "Some Title")] [InlineData("sometitle", "Sometitle")] - [InlineData("some-title: The begining", "Some Title: The Begining")] - [InlineData("some_title:_the_begining", "Some Title: The Begining")] - [InlineData("some title: The_begining", "Some Title: The Begining")] + [InlineData("some-title: The beginning", "Some Title: The Beginning")] + [InlineData("some_title:_the_beginning", "Some Title: the Beginning")] + [InlineData("some title: The_beginning", "Some Title: The Beginning")] public void Titleize(string input, string expectedOuput) { Assert.Equal(expectedOuput, input.Titleize()); diff --git a/src/Humanizer.Tests.Shared/StringHumanizeTests.cs b/src/Humanizer.Tests.Shared/StringHumanizeTests.cs index 6b35eb0d5..cad79c1d0 100644 --- a/src/Humanizer.Tests.Shared/StringHumanizeTests.cs +++ b/src/Humanizer.Tests.Shared/StringHumanizeTests.cs @@ -71,6 +71,7 @@ public void CanHumanizeStringWithAcronyms(string input, string expectedValue) [Theory] [InlineData("CanReturnTitleCase", "Can Return Title Case")] [InlineData("Can_return_title_Case", "Can Return Title Case")] + [InlineData("In titles use lower case for prepositions an article or conjunctions", "In Titles Use Lower Case for Prepositions an Article or Conjunctions")] [InlineData("Title_humanization_Honors_ALLCAPS", "Title Humanization Honors ALLCAPS")] [InlineData("MühldorferStraße23", "Mühldorfer Straße 23")] [InlineData("mühldorfer_STRAẞE_23", "Mühldorfer STRAẞE 23")] diff --git a/src/Humanizer.Tests.Shared/TransformersTests.cs b/src/Humanizer.Tests.Shared/TransformersTests.cs index 6b872184d..342493295 100644 --- a/src/Humanizer.Tests.Shared/TransformersTests.cs +++ b/src/Humanizer.Tests.Shared/TransformersTests.cs @@ -9,7 +9,7 @@ public class TransformersTests [InlineData("Sentence casing", "Sentence Casing")] [InlineData("honors UPPER case", "Honors UPPER Case")] [InlineData("INvalid caSEs arE corrected", "Invalid Cases Are Corrected")] - [InlineData("Can deal w 1 letter words as i do", "Can Deal W 1 Letter Words As I Do")] + [InlineData("Can deal w 1 letter words as i do", "Can Deal W 1 Letter Words as I Do")] [InlineData(" random spaces are HONORED too ", " Random Spaces Are HONORED Too ")] [InlineData("Title Case", "Title Case")] [InlineData("apostrophe's aren't capitalized", "Apostrophe's Aren't Capitalized")] diff --git a/src/Humanizer/Transformer/ToTitleCase.cs b/src/Humanizer/Transformer/ToTitleCase.cs index f0d34d438..b81260836 100644 --- a/src/Humanizer/Transformer/ToTitleCase.cs +++ b/src/Humanizer/Transformer/ToTitleCase.cs @@ -1,4 +1,5 @@ -using System.Globalization; +using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text.RegularExpressions; @@ -17,12 +18,14 @@ public string Transform(string input, CultureInfo culture) var result = input; var matches = Regex.Matches(input, @"(\w|[^\u0000-\u007F])+'?\w*"); + var firstWord = true; foreach (Match word in matches) { if (!AllCapitals(word.Value)) { - result = ReplaceWithTitleCase(word, result, culture); + result = ReplaceWithTitleCase(word, result, culture, firstWord); } + firstWord = false; } return result; @@ -33,10 +36,28 @@ private static bool AllCapitals(string input) return input.ToCharArray().All(char.IsUpper); } - private static string ReplaceWithTitleCase(Match word, string source, CultureInfo culture) + private static string ReplaceWithTitleCase(Match word, string source, CultureInfo culture, bool firstWord) { + var articles = new List { "a", "an", "the" }; + var conjunctions = new List { "and", "as", "but", "if", "nor", "or", "so", "yet" }; + var prepositions = new List { "as", "at", "by", "for", "in", "of", "off", "on", "to", "up", "via" }; + var wordToConvert = word.Value; - var replacement = culture.TextInfo.ToUpper(wordToConvert[0]) + culture.TextInfo.ToLower(wordToConvert.Remove(0, 1)); + string replacement; + + + if (firstWord || + (!articles.Contains(wordToConvert) && + !conjunctions.Contains(wordToConvert) && + !prepositions.Contains(wordToConvert))) + { + replacement = culture.TextInfo.ToUpper(wordToConvert[0]) + culture.TextInfo.ToLower(wordToConvert.Remove(0, 1)); + + } + else + { + replacement = culture.TextInfo.ToLower(wordToConvert); + } return source.Substring(0, word.Index) + replacement + source.Substring(word.Index + word.Length); } }