Skip to content

Commit 9101f5f

Browse files
Merge pull request #334 from atc-net/feature/improve-String-and-StringBuilder-Extensions
Improve SetStringFormatParameterTemplatePlaceholders and FormatWith method with overload for StringComparison to support model-properties mapping
2 parents fb51e4b + 7daaaa0 commit 9101f5f

File tree

13 files changed

+188
-30
lines changed

13 files changed

+188
-30
lines changed

docs/CodeDoc/Atc/IndexExtended.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5179,7 +5179,7 @@
51795179
- EnsureFirstCharacterToUpperAndSingular(this string value)
51805180
- EnsurePlural(this string value)
51815181
- EnsureSingular(this string value)
5182-
- FormatWith(this string template, string arg0, string arg1 = null, string arg2 = null, string arg3 = null, string arg4 = null, string arg5 = null, string arg6 = null, string arg7 = null, string arg8 = null, string arg9 = null, string arg0Name = null, string arg1Name = null, string arg2Name = null, string arg3Name = null, string arg4Name = null, string arg5Name = null, string arg6Name = null, string arg7Name = null, string arg8Name = null, string arg9Name = null)
5182+
- FormatWith(this string template, string arg0, string arg1 = null, string arg2 = null, string arg3 = null, string arg4 = null, string arg5 = null, string arg6 = null, string arg7 = null, string arg8 = null, string arg9 = null, StringComparison comparison = OrdinalIgnoreCase, string arg0Name = null, string arg1Name = null, string arg2Name = null, string arg3Name = null, string arg4Name = null, string arg5Name = null, string arg6Name = null, string arg7Name = null, string arg8Name = null, string arg9Name = null)
51835183
- GetStringFormatParameterLiteralCount(this string value)
51845184
- GetStringFormatParameterNumericCount(this string value)
51855185
- GetStringFormatParameterTemplatePlaceholders(this string value, bool useDoubleBracket = True)
@@ -5208,7 +5208,7 @@
52085208
- ReplaceNewLines(this string value, string newValue)
52095209
- ReplaceTemplateKeyWithValue(this string value, string templateKey, string templateValue, TemplatePatternType templatePatternType = HardBrackets)
52105210
- ReplaceTemplateKeysWithValues(this string value, IDictionary<string, string> templateKeyValues, TemplatePatternType templatePatternType = HardBrackets)
5211-
- SetStringFormatParameterTemplatePlaceholders(this string value, IDictionary<string, string> replacements, bool useDoubleBracket = True)
5211+
- SetStringFormatParameterTemplatePlaceholders(this string value, IDictionary<string, string> replacements, bool useDoubleBracket = True, StringComparison comparison = Ordinal)
52125212
- ToLines(this string value)
52135213
- ToStream(this string value)
52145214
- ToStreamFromBase64(this string base64Data)
@@ -5482,6 +5482,8 @@
54825482
- Static Methods
54835483
- Append(this StringBuilder sb, int indentSpaces, string value)
54845484
- Append(this StringBuilder sb, string format, object[] args)
5485+
- AppendLine(this StringBuilder sb, char value)
5486+
- AppendLine(this StringBuilder sb, int indentSpaces, char value)
54855487
- AppendLine(this StringBuilder sb, int indentSpaces, string value)
54865488
- AppendLine(this StringBuilder sb, string format, object[] args)
54875489

docs/CodeDoc/Atc/System.Text.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,24 @@ Extensions for the `System.Text.StringBuilder` class.
5656
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`sb`&nbsp;&nbsp;-&nbsp;&nbsp;The .<br />
5757
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`format`&nbsp;&nbsp;-&nbsp;&nbsp;A composite format string.<br />
5858
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`args`&nbsp;&nbsp;-&nbsp;&nbsp;An object array that contains zero or more objects to format.<br />
59+
#### AppendLine
60+
>```csharp
61+
>void AppendLine(this StringBuilder sb, char value)
62+
>```
63+
><b>Summary:</b> Appends a new line with formatting options to the string builder.
64+
>
65+
><b>Parameters:</b><br>
66+
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`sb`&nbsp;&nbsp;-&nbsp;&nbsp;The .<br />
67+
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`format`&nbsp;&nbsp;-&nbsp;&nbsp;A composite format string.<br />
68+
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`args`&nbsp;&nbsp;-&nbsp;&nbsp;An object array that contains zero or more objects to format.<br />
69+
#### AppendLine
70+
>```csharp
71+
>void AppendLine(this StringBuilder sb, int indentSpaces, char value)
72+
>```
73+
><b>Summary:</b> Appends a new line with formatting options to the string builder.
74+
>
75+
><b>Parameters:</b><br>
76+
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`sb`&nbsp;&nbsp;-&nbsp;&nbsp;The .<br />
77+
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`format`&nbsp;&nbsp;-&nbsp;&nbsp;A composite format string.<br />
78+
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`args`&nbsp;&nbsp;-&nbsp;&nbsp;An object array that contains zero or more objects to format.<br />
5979
<hr /><div style='text-align: right'><i>Generated by MarkdownCodeDoc version 1.2</i></div>

docs/CodeDoc/Atc/System.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2101,7 +2101,7 @@ Extensions for the string class.
21012101
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`value`&nbsp;&nbsp;-&nbsp;&nbsp;The value.<br />
21022102
#### FormatWith
21032103
>```csharp
2104-
>string FormatWith(this string template, string arg0, string arg1 = null, string arg2 = null, string arg3 = null, string arg4 = null, string arg5 = null, string arg6 = null, string arg7 = null, string arg8 = null, string arg9 = null, string arg0Name = null, string arg1Name = null, string arg2Name = null, string arg3Name = null, string arg4Name = null, string arg5Name = null, string arg6Name = null, string arg7Name = null, string arg8Name = null, string arg9Name = null)
2104+
>string FormatWith(this string template, string arg0, string arg1 = null, string arg2 = null, string arg3 = null, string arg4 = null, string arg5 = null, string arg6 = null, string arg7 = null, string arg8 = null, string arg9 = null, StringComparison comparison = OrdinalIgnoreCase, string arg0Name = null, string arg1Name = null, string arg2Name = null, string arg3Name = null, string arg4Name = null, string arg5Name = null, string arg6Name = null, string arg7Name = null, string arg8Name = null, string arg9Name = null)
21052105
>```
21062106
><b>Summary:</b> Formats a string template by replacing placeholders with corresponding argument values.
21072107
>
@@ -2117,6 +2117,7 @@ Extensions for the string class.
21172117
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`arg7`&nbsp;&nbsp;-&nbsp;&nbsp;Optional argument for placeholder replacement.<br />
21182118
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`arg8`&nbsp;&nbsp;-&nbsp;&nbsp;Optional argument for placeholder replacement.<br />
21192119
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`arg9`&nbsp;&nbsp;-&nbsp;&nbsp;Optional argument for placeholder replacement.<br />
2120+
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`comparison`&nbsp;&nbsp;-&nbsp;&nbsp;Use comparison with default for key matching.<br />
21202121
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`arg0Name`&nbsp;&nbsp;-&nbsp;&nbsp;The name of , provided via .<br />
21212122
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`arg1Name`&nbsp;&nbsp;-&nbsp;&nbsp;The name of (if provided), automatically inferred.<br />
21222123
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`arg2Name`&nbsp;&nbsp;-&nbsp;&nbsp;The name of (if provided), automatically inferred.<br />
@@ -2420,14 +2421,15 @@ Extensions for the string class.
24202421
><b>Returns:</b> The modified input string with template keys replaced by their corresponding template values.
24212422
#### SetStringFormatParameterTemplatePlaceholders
24222423
>```csharp
2423-
>string SetStringFormatParameterTemplatePlaceholders(this string value, IDictionary<string, string> replacements, bool useDoubleBracket = True)
2424+
>string SetStringFormatParameterTemplatePlaceholders(this string value, IDictionary<string, string> replacements, bool useDoubleBracket = True, StringComparison comparison = Ordinal)
24242425
>```
24252426
><b>Summary:</b> Sets the string format parameter template placeholders.
24262427
>
24272428
><b>Parameters:</b><br>
24282429
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`value`&nbsp;&nbsp;-&nbsp;&nbsp;The value.<br />
24292430
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`replacements`&nbsp;&nbsp;-&nbsp;&nbsp;The replacements.<br />
24302431
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`useDoubleBracket`&nbsp;&nbsp;-&nbsp;&nbsp;Use double bracket if ;otherwise .<br />
2432+
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`comparison`&nbsp;&nbsp;-&nbsp;&nbsp;Use comparison with default for key matching.<br />
24312433
#### ToLines
24322434
>```csharp
24332435
>string[] ToLines(this string value)

src/Atc.XUnit/CodeComplianceTestHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ public static string CollectExportedTypesWithMissingTestsAndGenerateText(
165165

166166
var sb = new StringBuilder();
167167
sb.AppendLine(12, "var excludeTypes = new List<Type>");
168-
sb.AppendLine(12, "{");
168+
sb.AppendLine(12, '{');
169169
sb.AppendLine(12, "{ // TODO: Implement tests on the following types, and then remove the type from the exclude list.");
170170
for (var i = 0; i < typesWithMissingTests.Length; i++)
171171
{

src/Atc/Extensions/StringBuilderExtensions.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,33 @@ public static void AppendLine(
121121

122122
sb.AppendLine(value.PadLeft(value.Length + indentSpaces));
123123
}
124+
125+
/// <summary>
126+
/// Appends a new line with indented spaces to the string builder.
127+
/// </summary>
128+
/// <param name="sb">The <see cref="StringBuilder"/>.</param>
129+
/// <param name="value">The value.</param>
130+
public static void AppendLine(
131+
this StringBuilder sb,
132+
char value)
133+
{
134+
if (sb is null)
135+
{
136+
throw new ArgumentNullException(nameof(sb));
137+
}
138+
139+
sb.AppendLine(value.ToString());
140+
}
141+
142+
/// <summary>
143+
/// Appends a new line with indented spaces to the string builder.
144+
/// </summary>
145+
/// <param name="sb">The <see cref="StringBuilder"/>.</param>
146+
/// <param name="indentSpaces">The indent spaces.</param>
147+
/// <param name="value">The value.</param>
148+
public static void AppendLine(
149+
this StringBuilder sb,
150+
int indentSpaces,
151+
char value)
152+
=> AppendLine(sb, indentSpaces, value.ToString());
124153
}

src/Atc/Extensions/StringExtensions.cs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ in matches
257257
/// <param name="value">The value.</param>
258258
/// <param name="replacements">The replacements.</param>
259259
/// <param name="useDoubleBracket">Use double bracket if <see langword="true" />;otherwise <see langword="false" />.</param>
260+
/// <param name="comparison">Use comparison with default <see langword="StringComparison.Ordinal" /> for key matching.</param>
260261
/// <exception cref="ArgumentNullException">
261262
/// value
262263
/// or
@@ -265,7 +266,8 @@ in matches
265266
public static string SetStringFormatParameterTemplatePlaceholders(
266267
this string value,
267268
IDictionary<string, string> replacements,
268-
bool useDoubleBracket = true)
269+
bool useDoubleBracket = true,
270+
StringComparison comparison = StringComparison.Ordinal)
269271
{
270272
if (value is null)
271273
{
@@ -284,8 +286,8 @@ public static string SetStringFormatParameterTemplatePlaceholders(
284286
{
285287
var s = (pair.Key.StartsWith("{{", StringComparison.Ordinal) &&
286288
pair.Key.EndsWith("}}", StringComparison.Ordinal)
287-
? placeholders.Find(x => string.Equals(x, pair.Key, StringComparison.Ordinal))
288-
: placeholders.Find(x => string.Equals(x, "{{" + pair.Key + "}}", StringComparison.Ordinal)))!;
289+
? placeholders.Find(x => string.Equals(x, pair.Key, comparison))
290+
: placeholders.Find(x => string.Equals(x, "{{" + pair.Key + "}}", comparison)))!;
289291

290292
if (!string.IsNullOrEmpty(s))
291293
{
@@ -297,10 +299,10 @@ public static string SetStringFormatParameterTemplatePlaceholders(
297299
{
298300
foreach (var pair in replacements)
299301
{
300-
var s = (pair.Key.StartsWith("{", StringComparison.Ordinal) &&
301-
pair.Key.EndsWith("}", StringComparison.Ordinal)
302-
? placeholders.Find(x => string.Equals(x, pair.Key, StringComparison.Ordinal))
303-
: placeholders.Find(x => string.Equals(x, "{" + pair.Key + "}", StringComparison.Ordinal)))!;
302+
var s = (pair.Key.StartsWith('{') &&
303+
pair.Key.EndsWith('}')
304+
? placeholders.Find(x => string.Equals(x, pair.Key, comparison))
305+
: placeholders.Find(x => string.Equals(x, '{' + pair.Key + '}', comparison)))!;
304306

305307
if (!string.IsNullOrEmpty(s))
306308
{
@@ -2022,6 +2024,7 @@ public static bool TryParseToHttpStatusCode(
20222024
/// <param name="arg7">Optional argument for placeholder replacement.</param>
20232025
/// <param name="arg8">Optional argument for placeholder replacement.</param>
20242026
/// <param name="arg9">Optional argument for placeholder replacement.</param>
2027+
/// <param name="comparison">Use comparison with default <see langword="StringComparison.OrdinalIgnoreCase" /> for key matching.</param>
20252028
/// <param name="arg0Name">The name of <paramref name="arg0"/>, provided via <see cref="CallerArgumentExpressionAttribute"/>.</param>
20262029
/// <param name="arg1Name">The name of <paramref name="arg1"/> (if provided), automatically inferred.</param>
20272030
/// <param name="arg2Name">The name of <paramref name="arg2"/> (if provided), automatically inferred.</param>
@@ -2047,6 +2050,8 @@ public static bool TryParseToHttpStatusCode(
20472050
/// - Named placeholders (e.g., '{argName}') and indexed placeholders (e.g., '{0}') are supported.<br/>
20482051
/// - Argument names are inferred using the <see cref="CallerArgumentExpressionAttribute"/> for better debugging.
20492052
/// </remarks>
2053+
[SuppressMessage("Critical Code Smell", "S3776:Cognitive Complexity of methods should not be too high", Justification = "OK.")]
2054+
[SuppressMessage("Design", "MA0051:Method is too long", Justification = "OK.")]
20502055
public static string FormatWith(
20512056
this string template,
20522057
string arg0,
@@ -2059,6 +2064,7 @@ public static string FormatWith(
20592064
string? arg7 = null,
20602065
string? arg8 = null,
20612066
string? arg9 = null,
2067+
StringComparison comparison = StringComparison.OrdinalIgnoreCase,
20622068
[CallerArgumentExpression("arg0")] string arg0Name = null!,
20632069
[CallerArgumentExpression("arg1")] string? arg1Name = null,
20642070
[CallerArgumentExpression("arg2")] string? arg2Name = null,
@@ -2092,6 +2098,23 @@ public static string FormatWith(
20922098
var key = placeholder.Trim('{', '}');
20932099

20942100
var index = Array.IndexOf(argNames, key);
2101+
if (index == -1)
2102+
{
2103+
for (var i = 0; i < argNames.Length; i++)
2104+
{
2105+
if (argNames[i] == null)
2106+
{
2107+
break;
2108+
}
2109+
2110+
if (argNames[i]!.Contains('.', StringComparison.Ordinal) &&
2111+
argNames[i]!.EndsWith(key, comparison))
2112+
{
2113+
index = i;
2114+
}
2115+
}
2116+
}
2117+
20952118
if (index != -1 && index < usedArgsCount)
20962119
{
20972120
dictionary.Add(key, argValues[index]!);
@@ -2111,7 +2134,10 @@ public static string FormatWith(
21112134
}
21122135
}
21132136

2114-
return template.SetStringFormatParameterTemplatePlaceholders(dictionary, useDoubleBracket: false);
2137+
return template.SetStringFormatParameterTemplatePlaceholders(
2138+
dictionary,
2139+
useDoubleBracket: false,
2140+
comparison: StringComparison.OrdinalIgnoreCase);
21152141
}
21162142
#endif
21172143

test/Atc.Console.Spectre.Tests/SampleIntegrationTests/SampleIntegrationTestBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ public static void PrepareCliAppSettings(ConsoleLoggerConfiguration config)
3232
var jsonPart = json.Replace(Environment.NewLine, $"{Environment.NewLine} ", StringComparison.Ordinal);
3333

3434
var sbJson = new StringBuilder();
35-
sbJson.AppendLine("{");
35+
sbJson.AppendLine('{');
3636
sbJson.AppendLine(" \"ConsoleLogger\": " + jsonPart);
37-
sbJson.AppendLine("}");
37+
sbJson.AppendLine('}');
3838

3939
var jsonOutput = sbJson.ToString();
4040
File.WriteAllText(appSettingsFile.FullName, jsonOutput);

test/Atc.DotNet.Tests/DotnetBuildHelperTests.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,15 @@ private static Task CreateProgramFile(DirectoryInfo workingDirectory, bool withE
7373
sb.AppendLine("using System;");
7474
sb.AppendLine();
7575
sb.AppendLine("namespace Test");
76-
sb.AppendLine("{");
76+
sb.AppendLine('{');
7777
sb.AppendLine(4, "class Program");
78-
sb.AppendLine(4, "{");
78+
sb.AppendLine(4, '{');
7979
sb.AppendLine(8, "static void Main(string[] args)");
80-
sb.AppendLine(8, "{");
80+
sb.AppendLine(8, '{');
8181
sb.AppendLine(12, withError ? "QQConsole.WriteLine(\"Hello World!\");" : "Console.WriteLine(\"Hello World!\");");
82-
sb.AppendLine(8, "}");
83-
sb.AppendLine(4, "}");
84-
sb.AppendLine("}");
82+
sb.AppendLine(8, '}');
83+
sb.AppendLine(4, '}');
84+
sb.AppendLine('}');
8585

8686
return File.WriteAllTextAsync(file.FullName, sb.ToString(), Encoding.UTF8);
8787
}

test/Atc.DotNet.Tests/DotnetCsProjFileHelperTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -710,10 +710,10 @@ private static void CreateProgramCsFileBlazorServerApp(
710710
sb.AppendLine();
711711
sb.AppendLine("var app = builder.Build();");
712712
sb.AppendLine("if (!app.Environment.IsDevelopment())");
713-
sb.AppendLine("{");
713+
sb.AppendLine('{');
714714
sb.AppendLine(" app.UseExceptionHandler(\"/Error\");");
715715
sb.AppendLine(" app.UseHsts();");
716-
sb.AppendLine("}");
716+
sb.AppendLine('}');
717717
sb.AppendLine();
718718
sb.AppendLine("app.UseHttpsRedirection();");
719719
sb.AppendLine("app.UseStaticFiles();");

test/Atc.Tests/ConsoleEmojiConstantsTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ private static string GenerateContent(IList<(string Group, string SubGroup, stri
7070
sb.AppendLine($"/// Generated from: {SourceUrl}");
7171
sb.AppendLine("/// </Remarks>");
7272
sb.AppendLine("public static partial class EmojiConstants");
73-
sb.AppendLine("{");
73+
sb.AppendLine('{');
7474
var isFirst = true;
7575
foreach (var groupName in groupNames)
7676
{

0 commit comments

Comments
 (0)