0

is possible to make interpolation based on user input?

For example something like this:

public string Foo(string input)
{
    string user = "random_user_name";
    string address = "random_address";
    string city = "random_city";

    return $"{input}";
}
  • Example input1: "{user}, {city}"
  • Expected output1: "random_user_name, random_city"
  • Example input2: "{address}"
  • Expected output2: "random_address"
  • Example input3: "{city}, {address}"
  • Expected output3: "random_city, random_address"

I need that user can define which variables want and their order. Btw user will know variable names.

3
  • I don't think this is possible, and even if it were, what problem are you trying to solve? Commented Nov 4, 2021 at 23:57
  • Does this answer your question? Use of string as an existing variable in c# Commented Nov 4, 2021 at 23:57
  • 1
    There are many ways to do token replacement, and many libraries that give you a world of options, however a low tech approach is input.Replace("{user}", user ); Commented Nov 5, 2021 at 0:11

4 Answers 4

2

Taking @TheGeneral's suggestion, I did the following:

The first thing I did was to change your three strings into a Dictionary<string, string>

var tokens = new Dictionary<string, string> {
    { "user", "random_user_name" },
    { "address", "random_address" },
    { "city",  "random_city" }
};

Then I created a worker function that does the replacement in the way @TheGeneral described

public static string DoReplacement(string key, Dictionary<string, string> tokens)
{
    var result = new StringBuilder(key);
    foreach (var kvp in tokens)
    {
        result.Replace("{" + kvp.Key + "}", kvp.Value);
    }
    return result.ToString();
}

And finally, I wrapped it all together:

public static string Test(string input)
{
    var tokens = new Dictionary<string, string> {
        { "user", "random_user_name" },
        { "address", "random_address" },
        { "city",  "random_city" }
    };

    return $"{DoReplacement(input, tokens)}";
}

To exercise this, I called it with the OP's examples:

var tests = new List<string> {
    "{user}, {city}",
    "{address}",
    "{city}, {address}",
};
foreach (var s in tests)
{
    var replaced = StringReplacement.Test(s);
    Debug.WriteLine(replaced);
}

and got this output:

random_user_name, random_city
random_address
random_city, random_address
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for answer, this looks like solution of my problem :) but is it possible to make is much more simplified? Something like my "example code" in question?
How much more simplified do you think it can get? I replaced your three string variable declarations with a Dictionary having three members. Then I added a four line of code worker function (DoReplacement). The test code (with the list and the foreach) is nearly as complicated as the entire solution
Simpler version, as you insist: public string Foo(string input) => input.Replace("{user}", "random_user_name").Replace("{address}", "random_address").Replace("{city}", "random_city";
The advantage of a dictionary is that the code is somewhat declarative. You could also populate the dictionary from, say a database. But, yeah, if you want to boil it down to nothing...
1

Completely different technique to my other answer, this uses a regex matchevaluator to supply replacement values

Your code has a dictionary of replacements:

var tokens = new Dictionary<string, string> {
    { "{user}", "random_user_name" },
    { "{address}", "random_address" },
    { "{city}",  "random_city" }
};

We make a Regex out of the keys:

var r = new Regex(string.Join("|", tokens.Keys.Select(Regex.Escape)));

We make a matchevaluator, which is basically a method that decides what replacement value to use when the Regex finds some matching value:

var me = new MatchEvaluator(m => tokens[m.Value]);

And we call it on their input

var output = r.Replace(sInput, me);

Having built a string from the keys, like {user}|{address}|{city} the Regex will find these in OR style in the input string. Every time it finds one, it asks the match evaluator e.g. "found 'user' what do I replace it with?" and the match evaluator lambda basically looks "user" up in the dictionary and gives back "random_user_name"

Note, if you enable case insensitive matching on the Regex you should do something like lowercasing the keys in the dictionary and calling ToLower in the match evaluator lookup otherwise you might get keyNotFound

Comments

0

You can simply use string.Format

public string Foo(string input)
{
    string user = "random_user_name";
    string address = "random_address";
    string city = "random_city";

    return string.Format(input, user, address, city);
}

Examples

Foo("{0}, {2}")  // "random_user_name, random_city"
Foo("{1}")       // "random_address"
Foo("{2}, {1}")  // "random_city, random_address"

dotnetfiddle

The downside is that the user of the function needs to know which order you will pass the parameters.

Comments

0

Building on Charlieface's suggestion.. In the past I've taken the user's input and transformed it into a Format compatible input string because I know the order I will pass to format..

I know I call Format in weight, name, birthday order

I can do:

public class Formatter{

    private string _fmt;

    public Formatter(string theirInput){
      _fmt = theirInput;

      ord = new[] { "{weight", "{name", "{birthday" };
      for(int x = 0; x < ord.Length; x++)
        _fmt = _fmt.Replace(ord[x], "{"+x);
    }

    public string Format(User u){
      return string.Format(_fmt, u.Weight, u.Name, u.Birthday);
    }
}

Suppose the user types {name} {weight} {birthday}

This code transforms it to {1} {0} {2} then stores the transformation

Why bother? Well, if it's only going to happen one time you might as well just use the string replace pattern in the constructor to straight replace the variables with the values. The advantage of doing this is if you have multiple things to format in the same way and, bonus, it allows the user to specify formats that might vary by culture

For example your user could pass "Mr {name} born on {birthday:yyyy-MM-dd} weighing {weight:F2} lbs to two decimal places" and string.Format would adjust the formatting of their birthday DateTime to follow yyyy-MM-did and double Weight (which is calculated from kilos and might have 15 decimal places) to two decimal places.

You can read more about string formatting and parameters To placeholders in the docs:

https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings

https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings

https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings

https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings

https://learn.microsoft.com/en-us/dotnet/api/system.string.format?view=net-5.0

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.