From 86d429ac5169c533a707e8f734561a680c518a86 Mon Sep 17 00:00:00 2001 From: jesi318 Date: Fri, 3 Apr 2026 21:51:43 +0530 Subject: [PATCH 1/3] - fixed -ves issue by removing greedy[^f]ves and adding additional rule with tests --- src/Humanizer/Inflections/Vocabularies.cs | 6 ++++-- tests/Humanizer.Tests/InflectorTests.cs | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Humanizer/Inflections/Vocabularies.cs b/src/Humanizer/Inflections/Vocabularies.cs index 5b31baa0a..470f0324f 100644 --- a/src/Humanizer/Inflections/Vocabularies.cs +++ b/src/Humanizer/Inflections/Vocabularies.cs @@ -43,10 +43,11 @@ static Vocabulary BuildDefault() _default.AddSingular("(n)ews$", "$1ews"); _default.AddSingular("([dti])a$", "$1um"); _default.AddSingular("(analy|ba|diagno|parenthe|progno|synop|the|ellip|empha|neuro|oa|paraly)ses$", "$1sis"); - _default.AddSingular("([^f])ves$", "$1fe"); + _default.AddSingular("(.+)ves$", "$1ve"); _default.AddSingular("(hive)s$", "$1"); _default.AddSingular("(tive)s$", "$1"); - _default.AddSingular("([lr]|hoo|lea|loa|thie)ves$", "$1f"); + _default.AddSingular("(lea|loa|cal|hal|sel|el|shel|wol|thie|dwar|hoo)ves$", "$1f"); + _default.AddSingular("(li|wi|kni)ves$", "$1fe"); _default.AddSingular("(^zomb)?([^aeiouy]|qu)ies$", "$2y"); _default.AddSingular("(s)eries$", "$1eries"); _default.AddSingular("(m)ovies$", "$1ovie"); @@ -93,6 +94,7 @@ static Vocabulary BuildDefault() _default.AddIrregular("lens", "lenses"); _default.AddIrregular("clove", "cloves"); _default.AddIrregular("valve", "valves"); + _default.AddIrregular("safe", "safes"); _default.AddIrregular("explosive", "explosives"); _default.AddUncountable("staff"); diff --git a/tests/Humanizer.Tests/InflectorTests.cs b/tests/Humanizer.Tests/InflectorTests.cs index 10cd54062..9e4c2f9e5 100644 --- a/tests/Humanizer.Tests/InflectorTests.cs +++ b/tests/Humanizer.Tests/InflectorTests.cs @@ -60,6 +60,20 @@ public void SingularizeWordsWithUnknownSingularity(string singular, string plura public void SingularizeSkipSimpleWords(string singular, string plural) => Assert.Equal(singular, plural.Singularize(skipSimpleWords: true)); + [Theory] + [InlineData("arrives", "arrive")] + [InlineData("drives", "drive")] + [InlineData("curves", "curve")] + [InlineData("behaves", "behave")] + [InlineData("survives", "survive")] + [InlineData("derives", "derive")] + [InlineData("knives", "knife")] + [InlineData("wives", "wife")] + [InlineData("leaves", "leaf")] + [InlineData("lives", "life")] + public void Singularize_Ves_EdgeCases(string plural, string expected) => + Assert.Equal(expected, plural.Singularize()); + [Theory] [InlineData("a")] [InlineData("A")] From 864f993ce9e41bfc9c325117516246d03e9d2f68 Mon Sep 17 00:00:00 2001 From: jesi318 Date: Fri, 3 Apr 2026 21:54:31 +0530 Subject: [PATCH 2/3] - fixed the test for safe and safes --- tests/Humanizer.Tests/InflectorTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Humanizer.Tests/InflectorTests.cs b/tests/Humanizer.Tests/InflectorTests.cs index 9e4c2f9e5..222682540 100644 --- a/tests/Humanizer.Tests/InflectorTests.cs +++ b/tests/Humanizer.Tests/InflectorTests.cs @@ -203,7 +203,7 @@ public IEnumerator GetEnumerator() yield return ["index", "indices"]; yield return ["wife", "wives"]; - yield return ["safe", "saves"]; + yield return ["safe", "safes"]; yield return ["half", "halves"]; yield return ["glove", "gloves"]; From 6d5de66d58d7e55a85a8ebf8a1a108ff4bc27d80 Mon Sep 17 00:00:00 2001 From: jesi318 Date: Sun, 5 Apr 2026 01:41:00 +0530 Subject: [PATCH 3/3] - resolved comments and added changes --- src/Humanizer/Inflections/Vocabularies.cs | 4 +++- tests/Humanizer.Tests/InflectorTests.cs | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Humanizer/Inflections/Vocabularies.cs b/src/Humanizer/Inflections/Vocabularies.cs index 470f0324f..208432715 100644 --- a/src/Humanizer/Inflections/Vocabularies.cs +++ b/src/Humanizer/Inflections/Vocabularies.cs @@ -46,8 +46,9 @@ static Vocabulary BuildDefault() _default.AddSingular("(.+)ves$", "$1ve"); _default.AddSingular("(hive)s$", "$1"); _default.AddSingular("(tive)s$", "$1"); - _default.AddSingular("(lea|loa|cal|hal|sel|el|shel|wol|thie|dwar|hoo)ves$", "$1f"); + _default.AddSingular("([lr])ves$", "$1f"); _default.AddSingular("(li|wi|kni)ves$", "$1fe"); + _default.AddSingular("(thie|hoo|loa|lea)ves$", "$1f"); _default.AddSingular("(^zomb)?([^aeiouy]|qu)ies$", "$2y"); _default.AddSingular("(s)eries$", "$1eries"); _default.AddSingular("(m)ovies$", "$1ovie"); @@ -93,6 +94,7 @@ static Vocabulary BuildDefault() _default.AddIrregular("tie", "ties", matchEnding: false); _default.AddIrregular("lens", "lenses"); _default.AddIrregular("clove", "cloves"); + _default.AddIrregular("curve", "curves"); _default.AddIrregular("valve", "valves"); _default.AddIrregular("safe", "safes"); _default.AddIrregular("explosive", "explosives"); diff --git a/tests/Humanizer.Tests/InflectorTests.cs b/tests/Humanizer.Tests/InflectorTests.cs index 222682540..e78edffd2 100644 --- a/tests/Humanizer.Tests/InflectorTests.cs +++ b/tests/Humanizer.Tests/InflectorTests.cs @@ -71,6 +71,9 @@ public void SingularizeSkipSimpleWords(string singular, string plural) => [InlineData("wives", "wife")] [InlineData("leaves", "leaf")] [InlineData("lives", "life")] + [InlineData("scarves", "scarf")] + [InlineData("hooves", "hoof")] + [InlineData("thieves", "thief")] public void Singularize_Ves_EdgeCases(string plural, string expected) => Assert.Equal(expected, plural.Singularize());