using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; namespace Developpez.Dotnet.Text { /// /// Représente un modèle de chaine de caractères, où on peut utiliser des noms plutôt que des index /// pour les valeurs à remplacer. /// public class StringTemplate { private string _template; private static Regex _regex = new Regex(@"(?{+)(?\w+)(?:[^}]+)?(?}+)", RegexOptions.Compiled); /// /// Initialise une nouvelle instance de StringTemplate avec le template à utiliser /// /// Le template à utiliser. Le format est identique à celui accepté par String.Format, /// mais avec des noms à la place des index pour les valeurs à remplacer public StringTemplate(string template) { template.CheckArgumentNull("template"); this._template = template; ParseTemplate(); } private string _templateWithIndexes; private List _placeholders; private void ParseTemplate() { _placeholders = new List(); MatchEvaluator evaluator = (m) => { if (m.Success) { string open = m.Groups["open"].Value; string close = m.Groups["close"].Value; string key = m.Groups["key"].Value; string format = m.Groups["format"].Value; if (open.Length % 2 == 0) return m.Value; open = RemoveLastChar(open); close = RemoveLastChar(close); if (!_placeholders.Contains(key)) { _placeholders.Add(key); } int index = _placeholders.IndexOf(key); return string.Format("{0}{{{1}{2}}}{3}", open, index, format, close); } return m.Value; }; _templateWithIndexes = _regex.Replace(_template, evaluator); } private string RemoveLastChar(string str) { if (str.Length > 1) return str.Substring(0, str.Length - 1); else return string.Empty; } /// /// Convertit une chaine en StringTemplate /// /// La chaine à convertir /// Un StringTemplate utilisant la chaine convertie comme template public static implicit operator StringTemplate(string s) { return new StringTemplate(s); } /// /// Renvoie une chaine représentant cette instance de StringTemplate. /// /// Le template utilisé par ce StringTemplate public override string ToString() { return _template; } /// /// Remplace les placeholders du template par les valeurs fournies dans le dictionnaire spécifié /// /// Le dictionnaire contenant les valeurs pour les placeholders /// La chaine formattée public string Format(IDictionary values) { values.CheckArgumentNull("values"); object[] array = new object[_placeholders.Count]; for(int i = 0; i < _placeholders.Count; i++) { string key = _placeholders[i]; object value; if (!values.TryGetValue(key, out value)) { value = string.Format("{{{0}}}", key); } array[i] = value; } return string.Format(_templateWithIndexes, array); } private IDictionary MakeDictionary(object obj) { Dictionary dict = new Dictionary(); Type type = obj.GetType(); foreach (string propName in _placeholders) { var prop = type.GetProperty(propName); if (prop != null) dict.Add(propName, prop.GetValue(obj, null)); } return dict; } /// /// Remplace les placeholders du template par les valeurs fournies dans l'objet spécifié /// /// L'objet contenant les valeurs pour les placeholders. Chaque propriété de /// l'objet correspond à un placeholder du template /// La chaine formattée /// Cette méthode s'utilise typiquement avec un objet de type anonyme, créé avec la syntaxe /// new { nom1 = valeur1, nom2 = valeur2 } public string Format(object values) { return Format(MakeDictionary(values)); } /// /// Remplace les placeholders du template spécifié par les valeurs fournies dans le dictionnaire spécifié /// /// Le template à utiliser /// Le dictionnaire contenant les valeurs pour les placeholders /// La chaine formattée public static string Format(string template, IDictionary values) { return new StringTemplate(template).Format(values); } /// /// Remplace les placeholders du template par les valeurs fournies dans l'objet spécifié /// /// Le template à utiliser /// L'objet contenant les valeurs pour les placeholders. Chaque propriété de /// l'objet correspond à un placeholder du template /// La chaine formattée /// Cette méthode s'utilise typiquement avec un objet de type anonyme, créé avec la syntaxe /// new { nom1 = valeur1, nom2 = valeur2 } public static string Format(string template, object values) { return new StringTemplate(template).Format(values); } } }