5

I'm trying to format some string dynamically with available variables in a specific context/scope.

This strings would have parts with things like {{parameter1}}, {{parameter2}} and these variables would exist in the scope where I'll try to reformat the string. The variable names should match.

I looked for something like a dynamically string interpolation approach, or how to use FormattableStringFactory, but I found nothing that really gives me what I need.

var parameter1 = DateTime.Now.ToString();
var parameter2 = "Hello world!";
var retrievedString = "{{parameter2}} Today we're {{parameter1}}";
var result = MagicMethod(retrievedString, parameter1, parameter2);
// or, var result = MagicMethod(retrievedString, new { parameter1, parameter2 });

Is there an existing solution or should I (in MagicMethod) replace these parts in the retrievedString with matching members of the anonymous object given as parameter (using reflection or something like that)?

EDIT:

Finally, I created an extension method to handle this:

internal static string SpecialFormat(this string input, object parameters) {
  var type = parameters.GetType();
  System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex( "\\{(.*?)\\}" );
  var sb = new System.Text.StringBuilder();
  var pos = 0;

  foreach (System.Text.RegularExpressions.Match toReplace in regex.Matches( input )) {
    var capture = toReplace.Groups[ 0 ];
    var paramName = toReplace.Groups[ toReplace.Groups.Count - 1 ].Value;
    var property = type.GetProperty( paramName );
    if (property == null) continue;
    sb.Append( input.Substring( pos, capture.Index - pos) );
    sb.Append( property.GetValue( parameters, null ) );
    pos = capture.Index + capture.Length;
  }

  if (input.Length > pos + 1) sb.Append( input.Substring( pos ) );

  return sb.ToString();
}

and I call it like this:

var parameter1 = DateTime.Now.ToString();
var parameter2 = "Hello world!";
var retrievedString = "{parameter2} Today we're {parameter1}";
var result = retrievedString.SpecialFormat( new { parameter1, parameter2 } );

Now, I don't use double braces anymore.

1
  • There's nothing that is part of C#, you'll need a magic method. Commented Jul 9, 2018 at 9:22

3 Answers 3

8

You can use reflection coupled with an anonymous type to do this:

public string StringFormat(string input, object parameters)
{
    var properties = parameters.GetType().GetProperties();
    var result = input;

    foreach (var property in properties)
    {
        result = result.Replace(
            $"{{{{{property.Name}}}}}", //This is assuming your param names are in format "{{abc}}"
            property.GetValue(parameters).ToString());
    }

    return result;
}

And call it like this:

var result = StringFormat(retrievedString, new { parameter1, parameter2 });
Sign up to request clarification or add additional context in comments.

1 Comment

Hi DavidG, thank you for this method. This is exactly what I thought to do if I didn't found a more "native" .NET solution. I will use it with a StringBuilder, thank you !
3

While not understanding what is the dificulty you're having, I'm placing my bet on

Replace( string oldValue, string newValue )

You can replace your "tags" with data you want.

var parameter1 = DateTime.Now.ToString();
var parameter2 = "Hello world!";
var retrievedString = "{{parameter2}} Today we're {{parameter1}}";
var result = retrievedString.Replace("{{parameter2}}", parameter2).Replace({{parameter1}}, parameter1);

EDIT

Author mentioned that he's looking at something that will take parameters and iterate the list. It can be done by something like

public static void Main(string[] args)
    {
        //your "unmodified" srting
        string text = "{{parameter2}} Today we're {{parameter1}}";

        //key = tag(explicitly) value = new string
        Dictionary<string, string> tagToStringDict = new Dictionary<string,string>();

        //add tags and it's respective replacement
        tagToStringDict.Add("{{parameter1}}", "Foo");
        tagToStringDict.Add("{{parameter2}}", "Bar");

        //this returns your "modified string"
        changeTagWithText(text, tagToStringDict);
    }

    public static string changeTagWithText(string text, Dictionary<string, string> dict)
    {
        foreach (KeyValuePair<string, string> entry in dict)
        {
            //key is the tag ; value is the replacement
            text = text.Replace(entry.Key, entry.Value);
        }
        return text;
    }

The function changeTagWithText will return:

"Bar Today we're Foo"

Using this method you can add all the tags to the Dictionary and it'll replace all automatically.

2 Comments

I was assuming that the parameters and input string are dynamic, but this might do the job.
Hi, thank you for your response, the problem is that the list of parameters will be variable, so I prefer to use a method taking it as parameter(s) and iterate the list). And another problem is that I would like to do it in a performant way, "string.Replace": doesn't it creates a new string each time ?
1

If you know order of parameters, you can use string.Format() method (msdn). Then, your code will look like:

var parameter1 = DateTime.Now.ToString();
var parameter2 = "Hello world!";
var retrievedString = "{{0}} Today we're {{1}}";
var result = string.Format(retrievedString, parameter2, parameter1);

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.