web-dev-qa-db-fra.com

Comment fournir un espace réservé de chaîne personnalisé pour le format de chaîne

J'ai une ficelle 

string str ="Enter {0} patient name";

J'utilise string.format pour le formater.

String.Format(str, "Hello");

Maintenant, si je veux que le patient soit également extrait d'une configuration, je dois changer str en quelque chose comme "Enter {0} {1} name". Donc, il va remplacer le {1} par la deuxième valeur. Le problème est que je veux au lieu de {1} un autre format quelque chose comme {pat}. Mais lorsque j'essaie d'utiliser, cela génère une erreur. La raison pour laquelle je veux un format différent, c'est qu'il y a beaucoup de fichiers que je dois changer comme ceci (qui peuvent contenir {0}, {1}, etc.) J'ai donc besoin d'un espace réservé personnalisé qui peut être remplacé au moment de l'exécution.

26
Punit Singhi

Vous voudrez peut-être vérifier FormatWith 2.0 by James Newton-King . Il vous permet d'utiliser des noms de propriété comme jetons de formatage tels que:

var user = new User()
{
    Name = "Olle Wobbla",
    Age = 25
};

Console.WriteLine("Your name is {Name} and your age is {Age}".FormatWith(user));

Vous pouvez également l'utiliser avec des types anonymes.

UPDATE: Il y a aussi une solution par Scott Hanselman similaire, mais elle est implémentée comme un ensemble de méthodes d'extension sur Object au lieu de String.

UPDATE 2012: vous pouvez obtenir le package méthode d'extension NETFx String.FormatWith Extension de Calrius Consulting sur NuGet.org

UPDATE 2014: Il y a aussi StringFormat.NET et StringFormat de littlebit

50
Magnus Lindhe

Regex avec un MatchEvaluator semble une bonne option:

static readonly Regex re = new Regex(@"\{([^\}]+)\}", RegexOptions.Compiled);
static void Main()
{
    string input = "this {foo} is now {bar}.";
    StringDictionary fields = new StringDictionary();
    fields.Add("foo", "code");
    fields.Add("bar", "working");

    string output = re.Replace(input, delegate (Match match) {
        return fields[match.Groups[1].Value];
    });
    Console.WriteLine(output); // "this code is now working."
}
17
Marc Gravell
object[] myInts = new int[] {8,9}; 

Cependant, vous pouvez vous en tirer avec:

object[] myInts = new string[] { "8", "9" }; 
string bar = string.Format("{0} {1}", myInts); 
3
mujtaba Hyder

J'ai vu toutes les réponses ci-dessus, mais je ne pouvais pas bien poser la question :) 

Existe-t-il une raison particulière pour laquelle le code suivant ne répond pas à vos besoins?

string myFirstStr = GetMyFirstStrFromSomewhere();
string mySecondStr = GetMySecondStrFromSomewhere();

string result = "Enter " + myFirstStr + " " + mySecondStr + " name";
3
Chansik Im

Voici une autre version de ceci que j'ai trouvée ici: http://www.reddit.com/r/programming/comments/bodml/beef_up_params_in_c_5_to_solve_lambda_abuse/c0nrsf1

Toute solution à ce problème impliquera une réflexion, ce qui n’est pas idéal, mais voici son code avec quelques-uns des autres problèmes de performances majeurs résolus. (Aucune erreur de vérification. Ajoutez-le si vous le souhaitez.):

1) Utilise la réflexion directe à l'exécution, sans surcharge de DataBinder

2) N'utilise pas d'expressions régulières, utilise une analyse et un état en un seul passage.

3) Ne convertit pas la chaîne en chaîne intermédiaire, puis la convertit à nouveau au format final.

4) Alloue et concatène avec un seul StringBuilder au lieu de créer des chaînes partout et de les concaténer dans de nouvelles chaînes.

5) Supprime le temps système nécessaire à l'appel d'un délégué pour n opérations de remplacement.

6) En général, il s’agit d’un seul passage qui évolue de manière relativement linéaire (certains coûts pour chaque recherche d’hôte et chaque propriété imbriquée, mais c’est tout.)

public static string FormatWith(this string format, object source)
{
    StringBuilder sbResult = new StringBuilder(format.Length);
    StringBuilder sbCurrentTerm = new StringBuilder();
    char[] formatChars = format.ToCharArray();
    bool inTerm = false;
    object currentPropValue = source;

    for (int i = 0; i < format.Length; i++)
    {
        if (formatChars[i] == '{')
            inTerm = true;
        else if (formatChars[i] == '}')
        {
            PropertyInfo pi = currentPropValue.GetType().GetProperty(sbCurrentTerm.ToString());
            sbResult.Append((string)(pi.PropertyType.GetMethod("ToString", new Type[]{}).Invoke(pi.GetValue(currentPropValue, null), null)));
            sbCurrentTerm.Clear();
            inTerm = false;
            currentPropValue = source;
        }
        else if (inTerm)
        {
            if (formatChars[i] == '.')
            {
                PropertyInfo pi = currentPropValue.GetType().GetProperty(sbCurrentTerm.ToString());
                currentPropValue = pi.GetValue(source, null);
                sbCurrentTerm.Clear();
            }
            else
                sbCurrentTerm.Append(formatChars[i]);
        }
        else
            sbResult.Append(formatChars[i]);
    }
    return sbResult.ToString();
} 
2
Bryan Legend

Vous pouvez également utiliser l'exemple de Marc Gravell et étendre l'objet de classe String:

public static class StringExtension
{
    static readonly Regex re = new Regex(@"\{([^\}]+)\}", RegexOptions.Compiled);
    public static string FormatPlaceholder(this string str, Dictionary<string, string> fields)
    {
        if (fields == null)
            return str;

        return re.Replace(str, delegate(Match match)
        {
            return fields[match.Groups[1].Value];
        });

    }
}

Exemple d'utilisation:

String str = "I bought a {color} car";
Dictionary<string, string> fields = new Dictionary<string, string>();
fields.Add("color", "blue");

str.FormatPlaceholder(fields));
1
Ole K

Vous feriez probablement mieux d'utiliser Remplacer pour le champ personnalisé et Format pour le reste, comme:

string str = "Enter {0} {pat} name";
String.Format(str.Replace("{pat}", "Patient"), "Hello");
0
Dean Povey

Je voulais quelque chose qui fonctionne plus comme le formatage de chaîne de Python, alors j'ai écrit ceci: https://Gist.github.com/samwyse/b225b32ae1aea6fb27ad9c966b9ca90b

Utilisez-le comme ceci:

Dim template = New FormatFromDictionary("{cat} vs {dog}")
Dim d = New Dictionary(Of String, Object) From {
    {"cat", "Felix"}, {"dog", "Rex"}}
Console.WriteLine(template.Replace(d)) ' Felix vs Rex
0
samwyse