patterncsharpModerate
Putting everything in its place
Viewed 0 times
itsputtingeverythingplace
Problem
A new diagnostic has seen the light of day! This one will alert you when you have a
For each placeholder with index N, its value should be higher or equal to the placeholder at index N-1
If you want a more elaborate overview of what scenarios should be handled how you can take a look at the accompanying unit tests. I think I have covered all special scenarios in which placeholders can be used but since I get surprised by exotic scenarios all the time, please let me know if I forgot anything.
Unit tests Github
I omitted the tests because it would put my post way over the limited amount of characters.
Analyzer Github
```
using System.Collections.Immutable;
using System.Globalization;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
namespace VSDiagnostics.Diagnostics.Strings.StringPlaceholdersInWrongOrder
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class StringPlaceholdersInWrongOrderAnalyzer : DiagnosticAnalyzer
{
private static readonly string Category = VSDiagnosticsResources.StringsCategory;
private const string DiagnosticId = nameof(StringPlaceholdersInWrongOrderAnalyzer);
private static readonly string Message = VSDiagnosticsResources.StringPlaceholdersInWrongOrderMessage;
private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
private static readonly string Title = VSDiagnosticsResources.StringPlaceholdersInWrongOrderTitle;
internal static DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId, Title, Message, Category, Severity, true);
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeActi
string.Format() call where the formatting placeholders are in the wrong order. The right order is defined as:For each placeholder with index N, its value should be higher or equal to the placeholder at index N-1
If you want a more elaborate overview of what scenarios should be handled how you can take a look at the accompanying unit tests. I think I have covered all special scenarios in which placeholders can be used but since I get surprised by exotic scenarios all the time, please let me know if I forgot anything.
Unit tests Github
I omitted the tests because it would put my post way over the limited amount of characters.
Analyzer Github
```
using System.Collections.Immutable;
using System.Globalization;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
namespace VSDiagnostics.Diagnostics.Strings.StringPlaceholdersInWrongOrder
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class StringPlaceholdersInWrongOrderAnalyzer : DiagnosticAnalyzer
{
private static readonly string Category = VSDiagnosticsResources.StringsCategory;
private const string DiagnosticId = nameof(StringPlaceholdersInWrongOrderAnalyzer);
private static readonly string Message = VSDiagnosticsResources.StringPlaceholdersInWrongOrderMessage;
private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning;
private static readonly string Title = VSDiagnosticsResources.StringPlaceholdersInWrongOrderTitle;
internal static DiagnosticDescriptor Rule => new DiagnosticDescriptor(DiagnosticId, Title, Message, Category, Severity, true);
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeActi
Solution
private const string Pattern = @"(?<!\{)\{(?:\{\{)*(\d+(?::.*?)?)\}(?:\}\})*(?!\})";That pattern is the only reason you need a helper method like this:
/// Returns the placeholder index.
internal static string Normalize(string input)
{
var temp = input.Trim('{', '}');
var colonIndex = temp.IndexOf(':');
if (colonIndex > 0)
{
return temp.Remove(colonIndex);
}
return temp;
}You could leverage named groups and, on top of a more readable regex, you get named match groups and zero string-manipulation work needed to figure out the placeholder index:
"(?\d+)(?::.*?)?)\}(?:\}\})*(?!\})"That's it! Your index is given to you as part of the match!
Code Snippets
private const string Pattern = @"(?<!\{)\{(?:\{\{)*(\d+(?::.*?)?)\}(?:\}\})*(?!\})";/// <returns>Returns the placeholder index.</returns>
internal static string Normalize(string input)
{
var temp = input.Trim('{', '}');
var colonIndex = temp.IndexOf(':');
if (colonIndex > 0)
{
return temp.Remove(colonIndex);
}
return temp;
}"(?<!\{)\{(?:\{\{)*((?<index>\d+)(?::.*?)?)\}(?:\}\})*(?!\})"Context
StackExchange Code Review Q#101026, answer score: 10
Revisions (0)
No revisions yet.