Skip to content

Commit 96520db

Browse files
Enhance string comparison and refactor methods
Updated .editorconfig to set performance and globalization diagnostics to warnings. Refactored methods in InflectorExtensions.cs to use generated regex and extension method format. Improved string comparison across multiple files using StringComparison.Ordinal, StringComparison.OrdinalIgnoreCase, and culture-specific comparisons. Introduced static CultureInfo objects for consistent cultural formatting. Enhanced code readability and maintainability.
1 parent 4a51bff commit 96520db

15 files changed

+101
-95
lines changed

src/.editorconfig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,8 @@ dotnet_diagnostic.CA2241.severity = error
237237
dotnet_diagnostic.CA2242.severity = error
238238

239239

240-
# Test Projects
240+
dotnet_analyzer_diagnostic.category-Performance.severity = warning
241+
dotnet_analyzer_diagnostic.category-Globalization.severity = warning
241242

242243
# IDE0022: Use expression body for method
243244
dotnet_diagnostic.IDE0022.severity = silent

src/Humanizer/Bytes/ByteSize.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ readonly string ToString(string? format, IFormatProvider? provider, bool toSymbo
270270

271271
var formattedLargeWholeNumberValue = LargestWholeNumberValue.ToString(format, provider);
272272

273-
formattedLargeWholeNumberValue = formattedLargeWholeNumberValue.Equals(string.Empty)
273+
formattedLargeWholeNumberValue = formattedLargeWholeNumberValue.Equals(string.Empty, StringComparison.Ordinal)
274274
? "0"
275275
: formattedLargeWholeNumberValue;
276276

src/Humanizer/InflectorExtensions.cs

Lines changed: 52 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,22 @@ public static partial class InflectorExtensions
2828
#if NET7_0_OR_GREATER
2929
[GeneratedRegex(@"(?:[ _-]+|^)([a-zA-Z])")]
3030
private static partial Regex PascalizeRegexGenerated();
31-
31+
3232
private static Regex PascalizeRegex() => PascalizeRegexGenerated();
3333

3434
[GeneratedRegex(@"([\p{Lu}]+)([\p{Lu}][\p{Ll}])")]
3535
private static partial Regex UnderscoreRegex1Generated();
36-
36+
3737
private static Regex UnderscoreRegex1() => UnderscoreRegex1Generated();
3838

3939
[GeneratedRegex(@"([\p{Ll}\d])([\p{Lu}])")]
4040
private static partial Regex UnderscoreRegex2Generated();
41-
41+
4242
private static Regex UnderscoreRegex2() => UnderscoreRegex2Generated();
4343

4444
[GeneratedRegex(@"[-\s]")]
4545
private static partial Regex UnderscoreRegex3Generated();
46-
46+
4747
private static Regex UnderscoreRegex3() => UnderscoreRegex3Generated();
4848
#else
4949
private static readonly Regex PascalizeRegexField = new(@"(?:[ _-]+|^)([a-zA-Z])", RegexOptions.Compiled);
@@ -77,49 +77,57 @@ public static partial class InflectorExtensions
7777
public static string Singularize(this string word, bool inputIsKnownToBePlural = true, bool skipSimpleWords = false) =>
7878
Vocabularies.Default.Singularize(word, inputIsKnownToBePlural, skipSimpleWords);
7979

80-
/// <summary>
81-
/// Humanizes the input with Title casing
82-
/// </summary>
83-
/// <param name="input">The string to be titleized</param>
84-
public static string Titleize(this string input)
85-
{
86-
var humanized = input.Humanize();
87-
// If humanization returns empty string (no recognized letters), preserve original input
88-
return humanized.Length == 0 ? input : humanized.ApplyCase(LetterCasing.Title);
89-
}
90-
91-
/// <summary>
92-
/// By default, pascalize converts strings to UpperCamelCase also removing underscores
93-
/// </summary>
94-
public static string Pascalize(this string input) =>
95-
PascalizeRegex().Replace(input, match => match
96-
.Groups[1]
97-
.Value.ToUpper());
98-
99-
/// <summary>
100-
/// Same as Pascalize except that the first character is lower case
101-
/// </summary>
102-
public static string Camelize(this string input)
80+
extension(string input)
10381
{
104-
var word = input.Pascalize();
105-
return word.Length > 0
106-
? StringHumanizeExtensions.Concat(
107-
char.ToLower(word[0]),
108-
word.AsSpan(1))
109-
: word;
82+
/// <summary>
83+
/// Humanizes the input with Title casing
84+
/// </summary>
85+
public string Titleize()
86+
{
87+
var humanized = input.Humanize();
88+
// If humanization returns empty string (no recognized letters), preserve original input
89+
return humanized.Length == 0 ? input : humanized.ApplyCase(LetterCasing.Title);
90+
}
91+
92+
/// <summary>
93+
/// By default, pascalize converts strings to UpperCamelCase also removing underscores
94+
/// </summary>
95+
public string Pascalize() =>
96+
PascalizeRegex().Replace(input, match => match
97+
.Groups[1]
98+
.Value.ToUpper(CultureInfo.CurrentUICulture));
99+
100+
/// <summary>
101+
/// Same as Pascalize except that the first character is lower case
102+
/// </summary>
103+
public string Camelize()
104+
{
105+
var word = input.Pascalize();
106+
return word.Length > 0
107+
? StringHumanizeExtensions.Concat(
108+
char.ToLower(word[0]),
109+
word.AsSpan(1))
110+
: word;
111+
}
112+
113+
/// <summary>
114+
/// Separates the input words with underscore
115+
/// </summary>
116+
public string Underscore() =>
117+
UnderscoreRegex3()
118+
.Replace(
119+
UnderscoreRegex2().Replace(
120+
UnderscoreRegex1().Replace(input, "$1_$2"), "$1_$2"), "_")
121+
.ToLower(CultureInfo.CurrentUICulture);
122+
123+
/// <summary>
124+
/// Separates the input words with hyphens and all the words are converted to lowercase
125+
/// </summary>
126+
public string Kebaberize() =>
127+
Underscore(input)
128+
.Dasherize();
110129
}
111130

112-
/// <summary>
113-
/// Separates the input words with underscore
114-
/// </summary>
115-
/// <param name="input">The string to be underscored</param>
116-
public static string Underscore(this string input) =>
117-
UnderscoreRegex3()
118-
.Replace(
119-
UnderscoreRegex2().Replace(
120-
UnderscoreRegex1().Replace(input, "$1_$2"), "$1_$2"), "_")
121-
.ToLower();
122-
123131
/// <summary>
124132
/// Replaces underscores with dashes in the string
125133
/// </summary>
@@ -131,11 +139,4 @@ public static string Dasherize(this string underscoredWord) =>
131139
/// </summary>
132140
public static string Hyphenate(this string underscoredWord) =>
133141
Dasherize(underscoredWord);
134-
135-
/// <summary>
136-
/// Separates the input words with hyphens and all the words are converted to lowercase
137-
/// </summary>
138-
public static string Kebaberize(this string input) =>
139-
Underscore(input)
140-
.Dasherize();
141142
}

src/Humanizer/Localisation/Formatters/FrenchFormatter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Humanizer;
1+
namespace Humanizer;
22

33
class FrenchFormatter(CultureInfo culture) :
44
DefaultFormatter(culture)
@@ -12,7 +12,7 @@ protected override string GetResourceKey(string resourceKey, int number)
1212
return resourceKey + DualPostfix;
1313
}
1414

15-
if (number == 0 && resourceKey.StartsWith("TimeSpanHumanize_Multiple"))
15+
if (number == 0 && resourceKey.StartsWith("TimeSpanHumanize_Multiple", StringComparison.InvariantCulture))
1616
{
1717
return resourceKey + "_Singular";
1818
}

src/Humanizer/Localisation/NumberToWords/ArabicNumberToWordsConverter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ static string ParseNumber(string word, int number, GrammaticalGender gender)
265265
if (number <= 10)
266266
{
267267
var ordinals = gender == GrammaticalGender.Feminine ? FeminineOrdinalExceptions : OrdinalExceptions;
268-
foreach (var kv in ordinals.Where(kv => word.EndsWith(kv.Key)))
268+
foreach (var kv in ordinals.Where(kv => word.EndsWith(kv.Key, StringComparison.OrdinalIgnoreCase)))
269269
{
270270
// replace word with exception
271271
return StringHumanizeExtensions.Concat(
@@ -285,7 +285,7 @@ static string ParseNumber(string word, int number, GrammaticalGender gender)
285285
var oldPart = part;
286286

287287
var ordinals = gender == GrammaticalGender.Feminine ? FeminineOrdinalExceptions : OrdinalExceptions;
288-
foreach (var kv in ordinals.Where(kv => oldPart.EndsWith(kv.Key)))
288+
foreach (var kv in ordinals.Where(kv => oldPart.EndsWith(kv.Key, StringComparison.OrdinalIgnoreCase)))
289289
{
290290
// replace word with exception
291291
newPart = StringHumanizeExtensions.Concat(

src/Humanizer/Localisation/NumberToWords/BrazilianPortugueseNumberToWordsConverter.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ class BrazilianPortugueseNumberToWordsConverter :
1111
static readonly string[] OrdinalTensMap = ["zero", "décimo", "vigésimo", "trigésimo", "quadragésimo", "quinquagésimo", "sexagésimo", "septuagésimo", "octogésimo", "nonagésimo"];
1212
static readonly string[] OrdinalHundredsMap = ["zero", "centésimo", "ducentésimo", "trecentésimo", "quadringentésimo", "quingentésimo", "sexcentésimo", "septingentésimo", "octingentésimo", "noningentésimo"];
1313

14+
static readonly CultureInfo Culture = CultureInfo.GetCultureInfo("pt-BR");
15+
1416
public override string Convert(long input, GrammaticalGender gender, bool addAnd = true)
1517
{
1618
if (input is > 999999999999 or < -999999999999)
@@ -164,17 +166,17 @@ static string ApplyGender(string toWords, GrammaticalGender gender)
164166
return toWords;
165167
}
166168

167-
if (toWords.EndsWith("os"))
169+
if (toWords.EndsWith("os", StringComparison.OrdinalIgnoreCase))
168170
{
169171
return StringHumanizeExtensions.Concat(toWords.AsSpan(0, toWords.Length - 2), "as".AsSpan());
170172
}
171173

172-
if (toWords.EndsWith("um"))
174+
if (toWords.EndsWith("um", StringComparison.OrdinalIgnoreCase))
173175
{
174176
return StringHumanizeExtensions.Concat(toWords.AsSpan(0, toWords.Length - 2), "uma".AsSpan());
175177
}
176178

177-
if (toWords.EndsWith("dois"))
179+
if (toWords.EndsWith("dois", StringComparison.OrdinalIgnoreCase))
178180
{
179181
return StringHumanizeExtensions.Concat(toWords.AsSpan(0, toWords.Length - 4), "duas".AsSpan());
180182
}

src/Humanizer/Localisation/NumberToWords/CentralKurdishNumberToWordsConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public override string Convert(long number)
6868
}
6969

7070
var sentence = string.Join(" و ", parts);
71-
if (sentence.StartsWith("یەک هەزار"))
71+
if (sentence.StartsWith("یەک هەزار", StringComparison.OrdinalIgnoreCase))
7272
{
7373
return sentence[" یەک".Length..];
7474
}

src/Humanizer/Localisation/NumberToWords/DutchNumberToWordsConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ public override string ConvertToOrdinal(int number)
171171
{
172172
var word = Convert(number);
173173

174-
foreach (var kv in OrdinalExceptions.Where(kv => word.EndsWith(kv.Key)))
174+
foreach (var kv in OrdinalExceptions.Where(kv => word.EndsWith(kv.Key, StringComparison.Ordinal)))
175175
{
176176
// replace word with exception
177177
return StringHumanizeExtensions.Concat(word.AsSpan(0, word.Length - kv.Key.Length), kv.Value.AsSpan());

src/Humanizer/Localisation/NumberToWords/FrenchNumberToWordsConverterBase.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ abstract class FrenchNumberToWordsConverterBase : GenderedNumberToWordsConverter
44
{
55
static readonly string[] UnitsMap = ["zéro", "un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf", "dix", "onze", "douze", "treize", "quatorze", "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf"];
66
static readonly string[] TensMap = ["zéro", "dix", "vingt", "trente", "quarante", "cinquante", "soixante", "septante", "octante", "nonante"];
7+
static readonly CultureInfo Culture = CultureInfo.GetCultureInfo("fr");
78

89
public override string Convert(long number, GrammaticalGender gender, bool addAnd = true)
910
{
@@ -41,20 +42,20 @@ public override string ConvertToOrdinal(int number, GrammaticalGender gender)
4142

4243
var convertedNumber = Convert(number);
4344

44-
if (convertedNumber.EndsWith('s') && !convertedNumber.EndsWith("trois"))
45+
if (convertedNumber.EndsWith('s') && !convertedNumber.EndsWith("trois", true, Culture))
4546
{
4647
convertedNumber = convertedNumber.TrimEnd('s');
4748
}
48-
else if (convertedNumber.EndsWith("cinq"))
49+
else if (convertedNumber.EndsWith("cinq", true, Culture))
4950
{
5051
convertedNumber += "u";
5152
}
52-
else if (convertedNumber.EndsWith("neuf"))
53+
else if (convertedNumber.EndsWith("neuf", true, Culture))
5354
{
5455
convertedNumber = convertedNumber.TrimEnd('f') + "v";
5556
}
5657

57-
if (convertedNumber.StartsWith("un "))
58+
if (convertedNumber.StartsWith("un ", true, Culture))
5859
{
5960
convertedNumber = convertedNumber[3..];
6061
}

src/Humanizer/Localisation/NumberToWords/GreekNumberToWordsConverter.cs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Humanizer;
1+
namespace Humanizer;
22

33
class GreekNumberToWordsConverter : GenderlessNumberToWordsConverter
44
{
@@ -8,6 +8,7 @@ class GreekNumberToWordsConverter : GenderlessNumberToWordsConverter
88
static readonly string[] TensNoDiacriticsMap = ["", "δεκα", "εικοσι", "τριαντα", "σαραντα", "πενηντα", "εξηντα", "εβδομηντα", "ογδοντα", "ενενηντα"];
99
static readonly string[] HundredMap = ["", "εκατό", "διακόσια", "τριακόσια", "τετρακόσια", "πεντακόσια", "εξακόσια", "επτακόσια", "οκτακόσια", "εννιακόσια"];
1010
static readonly string[] HundredsMap = ["", "εκατόν", "διακόσιες", "τριακόσιες", "τετρακόσιες", "πεντακόσιες", "εξακόσιες", "επτακόσιες", "οκτακόσιες", "εννιακόσιες"];
11+
static readonly CultureInfo Culture = CultureInfo.GetCultureInfo("el");
1112

1213
static readonly FrozenDictionary<long, string> ΟrdinalMap = new Dictionary<long, string>
1314
{
@@ -265,7 +266,7 @@ string ConvertIntBH(long number, bool returnPluralized)
265266
}
266267

267268
result += ConvertImpl(number % 10, returnPluralized)
268-
.ToLower();
269+
.ToLower(Culture);
269270
}
270271

271272
return result;
@@ -291,7 +292,7 @@ string ConvertIntBT(long number, bool returnPluralized)
291292

292293
if (number % 100 != 0)
293294
{
294-
result += $" {ConvertImpl(number % 100, returnPluralized).ToLower()}";
295+
result += $" {ConvertImpl(number % 100, returnPluralized).ToLower(Culture)}";
295296
}
296297

297298
return result;
@@ -306,14 +307,14 @@ string ConvertIntBM(long number)
306307
return "χίλια";
307308
}
308309

309-
return $"χίλια {ConvertImpl(number % 1000, false).ToLower()}";
310+
return $"χίλια {ConvertImpl(number % 1000, false).ToLower(Culture)}";
310311
}
311312

312313
var result = $"{ConvertImpl(number / 1000, true)} χιλιάδες";
313314

314315
if (number % 1000 != 0)
315316
{
316-
result += $" {ConvertImpl(number % 1000, false).ToLower()}";
317+
result += $" {ConvertImpl(number % 1000, false).ToLower(Culture)}";
317318
}
318319

319320
return result;
@@ -328,14 +329,14 @@ string ConvertIntBB(long number)
328329
return "ένα εκατομμύριο";
329330
}
330331

331-
return $"ένα εκατομμύριο {ConvertImpl(number % 1000000, true).ToLower()}";
332+
return $"ένα εκατομμύριο {ConvertImpl(number % 1000000, true).ToLower(Culture)}";
332333
}
333334

334335
var result = $"{ConvertImpl(number / 1000000, false)} εκατομμύρια";
335336

336337
if (number % 1000000 != 0)
337338
{
338-
result += $" {ConvertImpl(number % 1000000, false).ToLower()}";
339+
result += $" {ConvertImpl(number % 1000000, false).ToLower(Culture)}";
339340
}
340341

341342
return result;
@@ -350,16 +351,16 @@ string ConvertIntBTR(long number)
350351
return "ένα δισεκατομμύριο";
351352
}
352353

353-
return $"ένα δισεκατομμύριο {ConvertImpl(number % 1000000000, true).ToLower()}";
354+
return $"ένα δισεκατομμύριο {ConvertImpl(number % 1000000000, true).ToLower(Culture)}";
354355
}
355356

356357
var result = $"{ConvertImpl(number / 1000000000, false)} δισεκατομμύρια";
357358

358359
if (number % 1000000000 != 0)
359360
{
360-
result += $" {ConvertImpl(number % 1000000000, false).ToLower()}";
361+
result += $" {ConvertImpl(number % 1000000000, false).ToLower(Culture)}";
361362
}
362363

363364
return result;
364365
}
365-
}
366+
}

0 commit comments

Comments
 (0)