web-dev-qa-db-fra.com

Comment formater un message avec des noms d'arguments au lieu de nombres?

J'ai quelque chose comme:

String text = "The user {0} has email address {1}."
// params = { "Robert", "[email protected]" }
String msg = MessageFormat.format(text, params);

Ce n'est pas génial pour moi, car parfois mes traducteurs ne sont pas sûrs de ce qui se passe dans les {0} et {1}, il serait également agréable de pouvoir reformuler les messages sans se soucier de l'ordre des arguments.

Je voudrais remplacer les arguments par des noms lisibles au lieu de nombres. Quelque chose comme ça:

String text = "The user {USERNAME} has email address {EMAILADDRESS}."
// Map map = new HashMap( ... [USERNAME="Robert", EMAILADDRESS="[email protected]"]
String msg = MessageFormat.format(text, map);

Y a-t-il un moyen facile de faire ceci?

Merci! Rob

52
Robert Hume

Vous pouvez utiliser MapFormat pour cela. Découvrez les détails ici:

http://www.Java2s.com/Code/Java/I18N/AtextformatsimilartoMessageFormatbutusingstringratherthannumerickeys.htm

String text = "The user {name} has email address {email}.";
            Object[] params = { "nameRobert", "[email protected]" };
            Map map = new HashMap();
            map.put("name", "Robert");
            map.put("email", "[email protected]");

System.out.println("1st : " + MapFormat.format(text, map));

SORTIE: 1er: L'utilisateur Robert a l'adresse e-mail [email protected].

29
GuruKulki

Voir StrSubstitutor de org.Apache.commons.lang3:

Map valuesMap = HashMap();
valuesMap.put("animal", "quick brown fox");
valuesMap.put("target", "lazy dog");
String templateString = "The ${animal} jumped over the ${target}.";
StrSubstitutor sub = new StrSubstitutor(valuesMap);
String resolvedString = sub.replace(templateString);

// resolvedString: "The quick brown fox jumped over the lazy dog."
17
AlikElzin-kilaka

Facile à faire vous-même. Voici ce que j'utilise (la fonction main() est juste pour le code de test):

import Java.util.HashMap;
import Java.util.Map;
import Java.util.regex.Matcher;
import Java.util.regex.Pattern;

public class StringTemplate {
    final private String template;
    final private Matcher m;
    static final private Pattern keyPattern = 
        Pattern.compile("\\$\\{([a-zA-Z][a-zA-Z0-9_]*(\\.[a-zA-Z][a-zA-Z0-9_]*)*)\\}");
    private boolean blanknull=false;

    public StringTemplate(String template) { 
        this.template=template;
        this.m = keyPattern.matcher(template);
    }

    /**
     * @param map substitution map
     * @return substituted string
     */
    public String substitute(Map<String, ? extends Object> map)
    {
        this.m.reset();
        StringBuffer sb = new StringBuffer();
        while (this.m.find())
        {
            String k0 = this.m.group();
            String k = this.m.group(1);
            Object vobj = map.get(k);
            String v = (vobj == null) 
                ? (this.blanknull ? "" : k0)
                : vobj.toString();
            this.m.appendReplacement(sb, Matcher.quoteReplacement(v));
        }
        this.m.appendTail(sb);
        return sb.toString();       
    }

    public StringTemplate setBlankNull()
    {
        this.blanknull=true;
        return this;
    }

    static public void main(String[] args)
    {
        StringTemplate t1 = new StringTemplate("${this} is a ${test} of the ${foo} bar=${bar} ${emergency.broadcasting.system}");
        t1.setBlankNull();
        Map<String, String> m = new HashMap<String, String>();
        m.put("this", "*This*");
        m.put("test", "*TEST*");
        m.put("foo", "$$$aaa\\\\111");
        m.put("emergency.broadcasting.system", "EBS");
        System.out.println(t1.substitute(m));
    }
}
11
Jason S

Votre question est étroitement liée à: Comment remplacer un ensemble de jetons dans une chaîne Java Vous pouvez utiliser vélocité ou une autre bibliothèque de modèles. Mais il y aura de la peine car Java n'a pas de littéraux Map.

2
kevin cline

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 modèle à part entière, vous pouvez jeter un œil à aleph-formatter (Je suis l'un des auteurs):

Student student = new Student("Andrei", 30, "Male");

String 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:

String 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 StringBuilder créant le résultat en "analysant" l'expression, aucune concaténation de chaîne, regex/replace n'est effectué.

2
Andrei Ciobanu
static final Pattern REPLACE_PATTERN = Pattern.compile("\\x24\\x7B([a-zA-Z][\\w\\x2E].*?)\\x7D");

/**
 * Check for unresolved environment
 *
 * @param str
 * @return Origin if all substitutions resolved
 */
public static String checkReplacement(String str) {
    Matcher matcher = REPLACE_PATTERN.matcher(str);
    if (matcher.find()) {
        throw LOG.getIllegalArgumentException("Environment variable '" + matcher.group(1) + "' is not defined");
    }
    return str;
}

// replace in str ${key} to value
public static String resolveReplacement(String str, Map<String, String> replacements) {
    Matcher matcher = REPLACE_PATTERN.matcher(str);
    while (matcher.find()) {
        String value = replacements.get(matcher.group(1));
        if (value != null) {
            str = matcher.replaceFirst(replaceWindowsSlash(value));
        }
    }
    return str;
}

Mais vous perdez toutes les options de format (comme ##. #)

1
GKislin