2009-07-09 4 views
24

J'ai une chaîneComment fournir espace réservé chaîne personnalisée pour le format de chaîne

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

J'utilise string.format pour formater.

String.Format(str, "Hello"); 

Maintenant, si je veux le patient aussi à récupérer dans une config alors je dois changer str à quelque chose comme "Enter {0} {1} name". Donc, il va remplacer le {1} avec la deuxième valeur. Le problème est que je veux au lieu de {1} un autre format quelque chose comme {pat}. Mais quand j'essaie d'utiliser, il y a une erreur. La raison pour laquelle je veux un format différent est qu'il y a beaucoup de fichiers que j'ai besoin de changer comme ceci (qui peut contenir {0}, {1} etc.). J'ai donc besoin d'un espace réservé personnalisé qui peut être remplacé lors de l'exécution.

Répondre

16

Regex avec 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." 
} 
47

Vous pouvez consulter FormatWith 2.0 par James Newton-King. Il vous permet d'utiliser les noms de propriétés que le formatage des jetons tels que celui-ci:

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.

MISE À JOUR: Il y a aussi un solution similaire en Scott Hanselman mais il est mis en œuvre un ensemble de méthodes d'extension sur Object au lieu de String.

MISE À JOUR 2012: Vous pouvez obtenir NETFx String.FormatWith Extension Method package NuGet de Calrius Consulting sur NuGet.org

MISE À JOUR 2014: Il y a aussi StringFormat.NET et littlebit's StringFormat

+1

+1. C'est intéressant, je n'ai jamais vu ça auparavant. On dirait que cela fonctionne bien avec les types anonymes. – RichardOD

+0

Dans l'article lié, certains commentateurs sont préoccupés par les performances. Assurez-vous de voir si la performance est acceptable avant de l'utiliser. –

+0

A dû aller avec la version de Scott puisque le FormatWith semble dépendre de System.Web. –

0

Vous êtes probablement mieux d'utiliser remplaçons pour le champ personnalisé et Format pour le reste, comme:

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

J'ai vu toutes les réponses ci-dessus, encore, je n'ai pas pu trouver la bonne question :)

Y at-il une raison particulière pour laquelle le code suivant ne répond pas à vos exigences?

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

string result = "Enter " + myFirstStr + " " + mySecondStr + " name"; 
2
object[] myInts = new int[] {8,9}; 

Cependant, vous pouvez vous en sortir avec:

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

Cela fonctionnera, mais le problème était que l'OP n'aimait pas l'espace réservé numérique {0} 'et en voulait un plus descriptif. –

2

Voici une autre version de ce que je trouve ici: http://www.reddit.com/r/programming/comments/bodml/beef_up_params_in_c_5_to_solve_lambda_abuse/c0nrsf1

Toute solution à cela va impliquer la réflexion, qui est moins qu'idéale, mais voici son code avec quelques-uns des autres problèmes de performance majeurs résolus. (Pas d'erreur de vérification Ajouter si vous le souhaitez..):

1) utilise la réflexion d'exécution directe, pas de frais généraux DataBinder

2) Ne pas utiliser des expressions régulières, utilise un seul passage Parse et de l'état.

3) Ne convertit pas la chaîne en une 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 de nouvelles chaînes un par un et de les concaténer en de nouvelles chaînes.

5) Supprime la surcharge de la pile d'appel d'un délégué pour n opérations de remplacement.

6) En général est un seul passage qui mettra à l'échelle d'une manière relativement linéaire (encore un peu de coût pour chaque pilier recherche et la recherche de prop imbriqué, mais c'est ça.)

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(); 
} 
0

Vous pouvez également utiliser l'exemple de Marc Gravell et d'é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)); 
0

Je voulais quelque chose qui fonctionnait plus comme la mise en forme de chaîne de Python, j'ai donc écrit ceci: https://gist.github.com/samwyse/b225b32ae1aea6fb27ad9c966b9ca90b

utiliser 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 
Questions connexes