How to replace {vars} in a string?

Asked

Viewed 1,385 times

7

I have a string

string str = "Bem vindo {Usuario}. Agora são: {Horas}";

I want to replace {Usuario} by a name and {Horas} by the current time, how can I do this?

4 answers

8

In C# 6 there is a new resource string where, depending on the goal, it is possible to set all this aside and leave the language/framework take care of it for you, so not the other answers no longer make sense in modern C# even if, of course, it works. So using:

string str = $"Bem vindo {Usuario}. Agora são: {Horas}"

I put in the Github for future reference.

You will already achieve the desired result since at the time of the evaluation of string you have the variables Usuario and Horas within the scope.

Read more on the subject.

7

C# already has a function for this, it is called String.Format see the documentation.

String.Format("Bem vindo {0}. Agora são: {1}", usuario, hora);

However if you want to implement something similar, you can use Regex as follows

var result = Regex.Replace(str, @"{(?<Parametro>[^}]+)}", m =>
{
    string variavel = m.Groups["Parametro"].Value; // Usuario, Horas
    switch (variavel)
    {
        case "Usuario": return usuario;
        case "Horas": return hora;
    }
    return "";
});

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

This allows you to access specific captured groups, through match.Groups["NomeDoGrupo"].Value.

This way you can capture the tokens and replace them as you wish.

Although this way is possible, I I suggest using the String.Format that has been well thought out, validated and is the standard for this type of operation.

  • 1

    The { and the } have special meaning in the regex syntax (ex: a{3,5}). It is allowed to insert them without any kind of escape thus?

  • 1

    Just as - has a special meaning ([a-z]) it only has that meaning in the specific context. Therefore it is not necessary to escape.

6


One idea is to use a IFormattable that understands its formats. For example, if you have such a class:

class Modelo : IFormattable {
  public string Usuario { get; set; }
  public DateTime Horas { get { return DateTime.Now; } }
  public string ToString(string format, IFormatProvider formatProvider) {
    if (format == "Usuario") return Usuario;
    if (format == "Horas") return Horas.ToString();
    throw new NotSupportedException();
  }
}

You can use it that way:

var modelo = new Modelo { Usuario = "Lobo" };
var strFinal = string.Format("Bem vindo {0:Usuario}. Agora são: {0:Horas}", modelo);

Note that you still need to use the index of the object that will replace it (in this case, 0).

You can implement IFormattable using reflection, for example, to replace any object property.

3

If your "{User}" key is fixed, it might be better to simply replace text instead of regular expressions. The Ers are very cool and powerful, but there is a certain computational cost to be paid.

With a very simple test using the ER suggestion offered by @Brunolm (which, by the way, was a very nice suggestion), you can see that the difference in processing time is quite considerable:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace ConsoleApplication2
{
    class Program
    {
        static string replace1(string str)
        {
            var result = Regex.Replace(str, @"{(?<Parametro>[^}]+)}", m =>
            {
                string variavel = m.Groups["Parametro"].Value; // Usuario, Horas
                switch (variavel)
                {
                    case "Usuario": return "Fulano da Silva";
                    case "Horas": return DateTime.Now.ToString("HH:mm:ss tt");
                }
                return "";
            });
            return result;
        }

        static string replace2(string str)
        {
            str = str.Replace("{Usuario}", "Beltrano da Silva");
            str = str.Replace("{Horas}", DateTime.Now.ToString("HH:mm:ss tt"));
            return str;
        }

        static void Main(string[] args)
        {

            string str = "Bem vindo {Usuario}. Agora são: {Horas}";

            DateTime dStart = DateTime.Now;
            Console.Out.WriteLine("Resultado 1: " + Program.replace1(str));
            DateTime dEnd = DateTime.Now;
            Console.Out.WriteLine("Duração: " + (dEnd - dStart).TotalMilliseconds);

            dStart = DateTime.Now;
            Console.Out.WriteLine("Resultado 2: " + Program.replace2(str));
            dEnd = DateTime.Now;
            Console.Out.WriteLine("Duração: " + (dEnd - dStart).TotalMilliseconds);
        }
    }
}

Produces the following output (duration in milliseconds):

Resultado 1: Bem vindo Fulano da Silva. Agora são: 15:28:15
Duração: 9,0005
Resultado 2: Bem vindo Beltrano da Silva. Agora são: 15:28:15
Duração: 1
  • A benchmark of a single repetition does not mean much. It would be necessary to make a loop to count at least 1 second. In addition it is interesting to repeat the entire benchmark more than once (in the same program) to prevent "warm up" time from being counted (how to initialize buffers exit). Another point is no print the result within the benchmark not to include this processing (can be quite unpredictable). Just one more point: compare equal things. One case replaces more characters than the other.

  • @Guilhermebernal: You are absolutely right, but my intention was only to illustrate that in fact 'there may be differences'. If the setting is as simple as it seemed, use ER can be an exaggeration. There’s a lot of discussion about it, actually. For example, in this thread and links referenced: http://stackoverflow.com/questions/9380062/is-using-a-regular-expression-faster-than-indexof

Browser other questions tagged

You are not signed in. Login or sign up in order to post.