2009-07-09 22 views
24

ho una stringa diCome fornire segnaposto stringa personalizzata per il formato stringa

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

Sto usando String.Format formattarlo.

String.Format(str, "Hello"); 

Ora, se voglio paziente anche essere recuperati da qualche config poi ho bisogno di cambiare str a qualcosa come "Enter {0} {1} name". Quindi sostituirà il {1} ​​con il secondo valore. Il problema è che voglio invece di {1} qualche altro formato qualcosa come {pat}. Ma quando provo a usare, genera un errore. La ragione per cui voglio un formato diverso è che ci sono molti file che ho bisogno di cambiare in questo modo (che può contenere {0}, {1}, ecc.). Quindi ho bisogno di un segnaposto personalizzato che possa essere sostituito in fase di esecuzione.

risposta

16

Regex con un MatchEvaluator sembra una buona opzione:

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

Si potrebbe voler controllare FormatWith 2.0 da James Newton-King. Esso consente di utilizzare nomi di proprietà come segni di formattazione come questo:

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

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

si può anche usare con i tipi anonimi.

UPDATE: C'è anche una simile solution da Scott Hanselman tuttavia è implementato come un insieme di metodi di estensione in Object anziché String.

UPDATE 2012: È possibile ottenere NETFx String.FormatWith Extension Method pacchetto NuGet di Calrius Consulenza sulla NuGet.org

UPDATE 2014: C'è anche StringFormat.NET e littlebit's StringFormat

+1

+1. È interessante, non l'ho mai visto prima. Sembra che funzioni bene con i tipi anonimi. – RichardOD

+0

Nell'articolo collegato alcuni commentatori sono preoccupati per le prestazioni. Assicurati di vedere se le prestazioni sono accettabili prima dell'uso. –

+0

Doveva andare con la versione di Scott poiché FormatWith sembra dipendere da System.Web. –

0

Siete probabilmente meglio usare Sostituire per il campo personalizzato e Formato per il resto, ad esempio:

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

Ho visto tutte le risposte sopra, tuttavia, non ho potuto ottenere la domanda giusta :)

C'è qualche ragione particolare per cui il codice seguente non soddisfa i tuoi requisiti?

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

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

Tuttavia è possibile farla franca:

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

Funzionerà, tuttavia il problema è che l'OP non ha gradito il segnaposto numerico '{0}' e ne voleva uno più descrittivo. –

2

Ecco un'altra versione di questo che ho trovato qui: http://www.reddit.com/r/programming/comments/bodml/beef_up_params_in_c_5_to_solve_lambda_abuse/c0nrsf1

Qualsiasi soluzione a questo sta per coinvolgere la riflessione, che non è l'ideale, ma ecco il suo codice con alcuni degli altri importanti problemi di prestazioni risolti. (Verifica nessun errore Aggiungi, se vuoi..):

1) utilizza la riflessione di esecuzione diretta, senza DataBinder sovraccarico

2) Non utilizzare le espressioni regolari, utilizza un parse single-pass e stato.

3) Non converte la stringa in una stringa intermedia e quindi la converte nuovamente nel formato finale.

4) Assegna e concatena con un singolo StringBuilder invece di creare nuove stringhe su tutto il luogo e concatenarle in nuove stringhe.

5) Rimuove il sovraccarico dello stack per chiamare un delegato per n operazioni di sostituzione.

6) In generale, è un singolo passaggio che si scala in modo relativamente lineare (ancora un certo costo per ogni ricerca prop e ricerca prop nidificati, ma questo è tutto.)

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

È possibile anche utilizzare nell'esempio di Marc Gravell ed estendere l'oggetto 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]; 
     }); 

    } 
} 

esempio utilizzo:

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

str.FormatPlaceholder(fields)); 
0

Volevo qualcosa che ha funzionato più come formattazione di stringhe di Python, così ho scritto questo: https://gist.github.com/samwyse/b225b32ae1aea6fb27ad9c966b9ca90b

usare in questo modo:

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 
Problemi correlati