How to replace tokens on a string template? [closed]

这一生的挚爱 提交于 2019-12-13 10:09:47

问题


I'm attempting to learn to write a basic template engine implementation. For example I have a string:

string originalString = "The current Date is: {{Date}}, the time is: {{Time}}";

what is the best way of reading the contents of each {{}} and then replacing the whole token with the valid string?

EDIT: Thanks to BrunoLM for pointing me in the right direction, so far this is what I have and it parses just fine, is there any other things I can do to optimize this function?

private const string RegexIncludeBrackets = @"{{(.*?)}}";

public static string ParseString(string input)
{
    return Regex.Replace(input, RegexIncludeBrackets, match =>
    {
        string cleanedString = match.Value.Substring(2, match.Value.Length - 4).Replace(" ", String.Empty);
        switch (cleanedString)
        {
            case "Date":
                return DateTime.Now.ToString("yyyy/MM/d");
            case "Time":
                return DateTime.Now.ToString("HH:mm");
            case "DateTime":
                return DateTime.Now.ToString(CultureInfo.InvariantCulture);
            default:
                return match.Value;
        }
    });
}

回答1:


Short answer

I think it would be best to use a Regex.

var result = Regex.Replace(str, @"{{(?<Name>[^}]+)}}", m =>
{
    return m.Groups["Name"].Value; // Date, Time
});

On c#-6.0 you can use:

string result = $"Time: {DateTime.Now}";

String.Format & IFormattable

However, there is a method for that already. Documentation.

String.Format("The current Date is: {0}, the time is: {1}", date, time);

And also, you can use a class with IFormattable. I didn't do performance tests but this one might be fast:

public class YourClass : IFormattable
{
    public string ToString(string format, IFormatProvider formatProvider)
    {
        if (format == "Date")
            return DateTime.Now.ToString("yyyy/MM/d");
        if (format == "Time")
            return DateTime.Now.ToString("HH:mm");
        if (format == "DateTime")
            return DateTime.Now.ToString(CultureInfo.InvariantCulture);

        return format;

        // or throw new NotSupportedException();
    }
}

And use as

String.Format("The current Date is: {0:Date}, the time is: {0:Time}", yourClass);

Review of your code and detailed information

In your current code you are using

// match.Value = {{Date}}
match.Value.Substring(2, match.Value.Length - 4).Replace(" ", String.Empty);

Instead, if you look at my code above, I used the pattern

@"{{(?<Name>[^}]+)}}"

The syntax (?<SomeName>.*) means this is a named group, you can check the documentation here.

It allows you to access match.Groups["SomeName"].Value which will be equivalent to the pattern with this group. So it would match two times, returning "Date" and then "Time", so you don't need to use SubString.

Updating your code, it would be

private const string RegexIncludeBrackets = @"{{(?<Param>.*?)}}";

public static string ParseString(string input)
{
    return Regex.Replace(input, RegexIncludeBrackets, match =>
    {
        string cleanedString = match.Groups["Param"].Value.Replace(" ", String.Empty);
        switch (cleanedString)
        {
            case "Date":
                return DateTime.Now.ToString("yyyy/MM/d");
            case "Time":
                return DateTime.Now.ToString("HH:mm");
            case "DateTime":
                return DateTime.Now.ToString(CultureInfo.InvariantCulture);
            default:
                return match.Value;
        }
    });
}

To improve even more, you can have a static compiled Regex field:

private static Regex RegexTemplate = new Regex(@"{{(?<Param>.*?)}}", RegexOptions.Compiled);

And then use as

RegexTemplate.Replace(str, match => ...);


来源:https://stackoverflow.com/questions/20651754/how-to-replace-tokens-on-a-string-template

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!