web-dev-qa-db-fra.com

Remplacement de chaîne en Java, similaire à un modèle de vélocité

Existe-t-il un mécanisme de remplacement de String en Java, dans lequel je peux transmettre des objets avec un texte, qui remplace la chaîne au fur et à mesure de son apparition.
Par exemple, le texte est:

Hello ${user.name},
    Welcome to ${site.name}. 

Les objets que j'ai sont: "user" Et "site". Je veux remplacer les chaînes données à l'intérieur de ${} Par ses valeurs équivalentes aux objets. C’est la même chose lorsque nous remplaçons des objets dans un modèle de vélocité.

77
Joe

Regardez le Java.text.MessageFormat classe, MessageFormat prend un ensemble d’objets, les formate, puis insère les chaînes mises en forme dans le modèle aux emplacements appropriés.

Object[] params = new Object[]{"hello", "!"};
String msg = MessageFormat.format("{0} world {1}", params);
115
RealHowTo

Utilisez StrSubstitutor d'Apache Commons Lang.

https://commons.Apache.org/proper/commons-lang/

Il le fera pour vous (et son source ouverte ...)

 Map<String, String> valuesMap = new HashMap<String, String>();
 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);
119
JH.

J'ai jeté ensemble une petite mise en œuvre de test de cela. L'idée de base est d'appeler format et de transmettre la chaîne de formatage, une carte d'objets et les noms qu'ils ont localement.

Le résultat de ce qui suit est:

Mon chien s'appelle fido, et Jane Doe le possède.

public class StringFormatter {

    private static final String fieldStart = "\\$\\{";
    private static final String fieldEnd = "\\}";

    private static final String regex = fieldStart + "([^}]+)" + fieldEnd;
    private static final Pattern pattern = Pattern.compile(regex);

    public static String format(String format, Map<String, Object> objects) {
        Matcher m = pattern.matcher(format);
        String result = format;
        while (m.find()) {
            String[] found = m.group(1).split("\\.");
            Object o = objects.get(found[0]);
            Field f = o.getClass().getField(found[1]);
            String newVal = f.get(o).toString();
            result = result.replaceFirst(regex, newVal);
        }
        return result;
    }

    static class Dog {
        public String name;
        public String owner;
        public String gender;
    }

    public static void main(String[] args) {
        Dog d = new Dog();
        d.name = "fido";
        d.owner = "Jane Doe";
        d.gender = "him";
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("d", d);
        System.out.println(
           StringFormatter.format(
                "My dog is named ${d.name}, and ${d.owner} owns ${d.gender}.", 
                map));
    }
}

Note: Ceci ne compile pas à cause d'exceptions non gérées. Mais cela rend le code beaucoup plus facile à lire.

De plus, je n'aime pas que vous ayez à construire la carte vous-même dans le code, mais je ne sais pas comment obtenir les noms des variables locales par programmation. La meilleure façon de le faire est de ne pas oublier de mettre l'objet dans la carte dès que vous le créez.

L'exemple suivant produit les résultats souhaités à partir de votre exemple:

public static void main(String[] args) {
    Map<String, Object> map = new HashMap<String, Object>();
    Site site = new Site();
    map.put("site", site);
    site.name = "StackOverflow.com";
    User user = new User();
    map.put("user", user);
    user.name = "jjnguy";
    System.out.println(
         format("Hello ${user.name},\n\tWelcome to ${site.name}. ", map));
}

Je devrais aussi mentionner que je n'ai aucune idée de ce qu'est Velocity, j'espère donc que cette réponse est pertinente.

18
jjnguy

Ma méthode préférée est String.format() car il s'agit d'un script unique et ne nécessite pas de bibliothèques tierces:

String result = String.format("Hello! My name is %s, I'm %s.", NameVariable, AgeVariable); 

J'utilise très souvent cela dans les messages d'exception, comme:

throw new Exception(String.format("Unable to login with email: %s", email));

Astuce: Vous pouvez mettre autant de variables que vous voulez parce que format() utilise Varargs

12
artgrohe

Voici un aperçu de la façon dont vous pourriez vous y prendre. Il devrait être relativement simple de l'implémenter en tant que code réel.

  1. Créez une carte de tous les objets qui seront référencés dans le modèle.
  2. Utilisez une expression régulière pour rechercher des références de variable dans le modèle et remplacez-les par leurs valeurs (voir l'étape 3). La classe Matcher sera utile pour rechercher et remplacer.
  3. Fractionner le nom de la variable au point. user.name deviendrait user et name. Recherchez user dans votre carte pour obtenir l'objet et utilisez réflexion pour obtenir la valeur de name à partir de l'objet. En supposant que vos objets aient des getters standard, vous allez rechercher une méthode getName et l'appeler.
5
casablanca

Il existe quelques implémentations d'Expression Language qui le font pour vous. Il serait peut-être préférable d'utiliser votre propre implémentation au fur et à mesure de l'évolution de vos besoins, voir par exemple JUEL et MVEL

J'aime et ai utilisé avec succès MVEL dans au moins un projet.

Voir aussi la publication Stackflow JSTL/JSP EL (Expression Language) dans un contexte non JSP (autonome)

4
Christoffer Soop

J'utilise GroovyShell dans Java pour analyser un modèle avec Groovy GString:

Binding binding = new Binding();
GroovyShell gs = new GroovyShell(binding);
// this JSONObject can also be replaced by any Java Object
JSONObject obj = new JSONObject();
obj.put("key", "value");
binding.setProperty("obj", obj)
String str = "${obj.key}";
String exp = String.format("\"%s\".toString()", str);
String res = (String) gs.evaluate(exp);
// value
System.out.println(str);
0
Kan

Rien n’est comparable à la vitesse, puisque vélocité a été écrit pour résoudre exactement ce problème. La chose la plus proche que vous pouvez essayer regarde dans le formateur

http://cupi2.uniandes.edu.co/site/images/recursos/javadoc/j2se/1.5.0/docs/api/Java/util/Formatter.html

Cependant, le formateur, pour autant que je sache, a été créé pour fournir des options de formatage similaires à C dans Java) afin de ne pas rayer votre démangeaison, mais n'hésitez pas à essayer :).

0
Mike Milkin