Formateur / formateur de chaîne de caractères Java avec arguments nommés

Existe-t-il une implémentation standard ou au moins généralisée de quelque chose comme Ssortingng.format , mais avec des arguments nommés?

J’aimerais formater une chaîne modélisée de la manière suivante:

 Map args = new HashMap(); args.put("PATH", "/usr/bin"); args.put("file", "foo"); Ssortingng s = someHypotheticalMethod("#{PATH}/ls #{file}"); // "/usr/bin/ls foo" 

Techniquement, c’est presque pareil à:

 Ssortingng[] args = new Ssortingng[] { "/usr/bin", "foo" }; Ssortingng s = Ssortingng.format("%1$s/ls %2$s", args); // "/usr/bin/ls foo" 

mais avec des arguments nommés.

Je suis conscient de:

  • Ssortingng.format
  • Formateur
  • MessageFormat

mais tous utilisent des arguments ordonnés ou au moins numérotés, non nommés. Je sais qu’il est simple d’en implémenter un, mais existe-t-il un mécanisme que je recherche dans les bibliothèques Java standard ou au moins dans Apache Commons / Guava / quelque chose de similaire, sans faire appel à des moteurs de modèles de haut niveau?

REMARQUE : je ne suis pas vraiment intéressé par les moteurs de modèles complets, avec des fonctionnalités telles que la logique impérative / fonctionnelle, le contrôle de stream, les modificateurs, les sous-modèles / inclusions, les iterators, etc. Généralement, la méthode suivante est une implémentation fonctionnelle à 4 lignes – c’est tout ce dont j’ai besoin:

 public static Ssortingng interpolate(Ssortingng format, Map args) { Ssortingng out = format; for (Ssortingng arg : args.keySet()) { out = Pattern.comstack(Pattern.quote("#{" + arg + "}")). matcher(out). replaceAll(args.get(arg).toSsortingng()); } return out; } 

Vous pouvez également essayer org.apache.commons.lang3.text.StrSubstitutor si Java 7 n’est pas une option. Il fait exactement ce que vous voulez qu’il fasse. Que ce soit léger ou non dépend de si vous utilisez également quelque chose d’autre de commons-lang.

Matcher # appendReplacement () serait utile

J’ai récemment découvert JUEL qui correspond bien à la description. C’est le langage d’expression extrait de JSP. Il prétend être très rapide aussi.

Je suis sur le sharepoint l’essayer dans l’un de mes propres projets.

Mais pour un poids plus léger, qui est une variante de vous, essayez ceci (enveloppé dans un test unitaire):

 public class TestInterpolation { public static class NamedFormatter { public final static Pattern pattern = Pattern.comstack("#\\{(?.*)}"); public static Ssortingng format(final Ssortingng format, Map kvs) { final SsortingngBuffer buffer = new SsortingngBuffer(); final Matcher match = pattern.matcher(format); while (match.find()) { final Ssortingng key = match.group("key"); final Object value = kvs.get(key); if (value != null) match.appendReplacement(buffer, value.toSsortingng()); else if (kvs.containsKey(key)) match.appendReplacement(buffer, "null"); else match.appendReplacement(buffer, ""); } match.appendTail(buffer); return buffer.toSsortingng(); } } @Test public void test() { assertEquals("hello world", NamedFormatter.format("hello #{name}", map("name", "world"))); assertEquals("hello null", NamedFormatter.format("hello #{name}", map("name", null))); assertEquals("hello ", NamedFormatter.format("hello #{name}", new HashMap())); } private Map map(final Ssortingng key, final Object value) { final Map kvs = new HashMap<>(); kvs.put(key, value); return kvs; } } 

Je l’étendrais pour append des méthodes pratiques pour des paires clé-valeur rapides

 format(format, key1, value1) format(format, key1, value1, key2, value2) format(format, key1, value1, key2, value2, key3, value3) ... 

Et il ne devrait pas être trop difficile de convertir de java 7+ à java 6-

SsortingngTemplate est peut-être un moteur d’interpolation aussi léger que possible, bien que j’ignore comment il emstack les ressources par rapport à des éléments tels que FreeMarker , Moustache ou Velocity .

Une autre option pourrait être un moteur EL comme MVEL , qui a un moteur de templates .

Voici ma solution:

 public class Template { private Pattern pattern; protected Map tokens; private Ssortingng template; public Template(Ssortingng template) { pattern = Pattern.comstack("\\$\\{\\w+\\}"); tokens = new HashMap(); this.template = template; } public void clearAllTokens() { tokens.clear(); } public void setToken(Ssortingng token, Ssortingng replacement) { if(token == null) { throw new NullPointerException("Token can't be null"); } if(replacement == null) { throw new NullPointerException("Replacement ssortingng can't be null"); } tokens.put(token, Matcher.quoteReplacement(replacement)); } public Ssortingng getText() { final Matcher matcher = pattern.matcher(template); final SsortingngBuffer sb = new SsortingngBuffer(); while(matcher.find()) { final Ssortingng entry = matcher.group(); final CharSequence key = entry.subSequence(2, entry.length() - 1); if(tokens.containsKey(key)) { matcher.appendReplacement(sb, tokens.get(key)); } } matcher.appendTail(sb); return sb.toSsortingng(); } public static void main(Ssortingng[] args) { Template template = new Template("Hello, ${name}."); template.setToken("name", "Eldar"); System.out.println(template.getText()); } } 

Je sais que ma réponse arrive un peu tard, mais si vous avez toujours besoin de cette fonctionnalité, sans avoir besoin de télécharger un moteur de template complet, vous pouvez jeter un coup d’œil à aleph-formateur (j’en suis l’un des auteurs):

 Student student = new Student("Andrei", 30, "Male"); Ssortingng studStr = template("#{id}\tName: #{st.getName}, Age: #{st.getAge}, Gender: #{st.getGender}") .arg("id", 10) .arg("st", student) .format(); System.out.println(studStr); 

Ou vous pouvez enchaîner les arguments:

 Ssortingng result = template("#{x} + #{y} = #{z}") .args("x", 5, "y", 10, "z", 15) .format(); System.out.println(result); // Output: "5 + 10 = 15" 

En interne, cela fonctionne en utilisant un SsortingngBuilder créant le résultat en “analysant” l’expression, aucune concaténation de chaîne, regex / replace n’est effectuée.