速度テンプレートに似た、Javaでの文字列置換


96

Stringオブジェクトをテキストで渡すことができるJavaの置換メカニズムはありますか?それは発生時に文字列を置き換えます。
たとえば、テキストは次のとおりです。

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

私が持っているオブジェクトがある"user""site"。内部${}で指定された文字列を、オブジェクトからの同等の値で置き換えます。これは、速度テンプレートのオブジェクトを置き換えるのと同じです。


1
どこを交換しますか?クラス?JSP?:あなただけの場合、文字列はformatメソッドを持っているString.format("Hello %s", username);
Droo

1
@Droo:この例では、文字列はのようなHello ${user.name}、ではない、Hello %sまたはHello {0}です。
Adeel Ansari、2010

2
速度のように見え、速度のような匂いがするものが必要な場合、それはおそらく速度ですか?:)
serg

@Droo:それはクラスではありません。上記のテキストを「String」変数に入れ、$ {}内のすべての文字列を対応するオブジェクトの値に置き換えたいと考えています。たとえば、すべての$ {user.name}を「user」オブジェクトのnameプロパティで置き換えます。
Joe

@serg:はい、速度コードです。コードからベロシティを削除したいと思います。
Joe

回答:


142

StringSubstitutorApache Commons Textから使用します。

https://commons.apache.org/proper/commons-text/

それはあなたのためにそれを行います(そしてそのオープンソース...)

 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}.";
 StringSubstitutor sub = new StringSubstitutor(valuesMap);
 String resolvedString = sub.replace(templateString);


1
する必要がありますMap<String, String> valuesMap = new HashMap<String, String>();
andrewrjones 2013

3
StrSubstitutorhttps://commons.apache.org/proper/commons-lang/で非推奨になりました。ユーザーの代わりにhttps://commons.apache.org/proper/commons-text/
Lukuluba

7
StrSubstitutor1.3で非推奨になりましたStringSubstitutor。代わりに使用してください。このクラスは2.0で削除されます。インポートのGradle依存関係StringSubstitutororg.apache.commons:commons-text:1.4
Yurii Rabeshko '27 / 09/27

条件ベースの置換が可能ですか?
gaurav

129

java.text.MessageFormatクラスを見てみましょう。MessageFormatは一連のオブジェクトを取得してフォーマットし、フォーマットされた文字列をパターンの適切な場所に挿入します。

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

10
ありがとう!私は、Javaがテンプレートエンジンを使用せずにこれを行う組み込みの方法を備えている必要があることを知っていました。
Joseph Rajeev Motha、2014年

2
String.Formatのはこれが何かできることを行うことができますように思える- stackoverflow.com/questions/2809633/...
ヌーメノン

6
+1。varargs formatも取るObject...ので、必要にformat("{0} world {1}", "Hello", "!");
応じて

それは注意すべきでMessageFormat確実にその同名、表示メッセージのため、出力ではなく技術的な書式設定事項についてのみを使用することができます。たとえば、数値はロケール設定ごとにフォーマットされ、技術的な使用には無効になります。
マルヌ

22

私の好きな方法は String.format()、それがワンライナーであり、サードパーティのライブラリを必要としないためです:

String message = String.format("Hello! My name is %s, I'm %s.", name, age); 

私はこれを定期的に使用します。たとえば、次のような例外メッセージで使用します。

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

ヒント:Varargsをformat()使用するため、変数はいくつでも入れることができます


同じ引数を2回以上繰り返す必要がある場合、これはあまり役に立ちません。例:String.format("Hello! My name is %s, I'm %s. Why is my name %s you ask? Well I'm only %s years old so I don't know", name, age, name, age);。ここでの他の回答では、各引数を1回だけ指定する必要があります。
アシャーバー

2
@asherbar書式指定文字列で引数インデックス指定子を使用できます。例String.format("Hello! My name is %1$s, I'm %2$s. Why is my name %1$s you ask? Well I'm only %2$s years old so I don't know", name, age)
jazzpi

@jazzpi知らなかった。ありがとう!
アシャーバー

20

私はこれの小さなテスト実装を一緒に投げました。基本的な考え方はformat、フォーマット文字列、オブジェクトのマップ、およびそれらがローカルに持つ名前を呼び出して渡すことです。

次の出力は次のとおりです。

私の犬はfidoという名前で、Jane Doeが飼っています。

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));
    }
}

注:これは、未処理の例外のためにコンパイルされません。しかし、それによってコードが非常に読みやすくなります。

また、コードで自分でマップを作成する必要があることは好ましくありませんが、ローカル変数の名前をプログラムで取得する方法がわかりません。それを行う最善の方法は、オブジェクトを作成したらすぐにマップに配置することを忘れないことです。

次の例は、例から必要な結果を生成します。

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));
}

また、Velocityが何であるかわからないので、この回答が関連していることを願っています。


これは私が探していたものです。実装していただきありがとうございます。私はそれを試みていて、不正確な結果を得ていました。:D とにかくそれは私の問題を解決しました。
Joe

2
@ジョー、助けてくれてうれしい。最後に、Javaでリフレクションを使用するコードの記述を練習するのは良い言い訳でした。
jjnguy

6

これを実行する方法の概要は次のとおりです。実際のコードとして実装するのは比較的簡単です。

  1. テンプレートで参照されるすべてのオブジェクトのマップを作成します。
  2. 正規表現を使用して、テンプレート内の変数参照を検索し、それらをその値に置き換えます(ステップ3を参照)。マッチャークラスは、検索と置換するために便利になるだろう。
  3. 変数名をドットで分割します。user.nameなるusername。見上げてuserオブジェクトを取得して使用するようにマップ内の反射をの値を取得するためにnameオブジェクトからを。オブジェクトに標準のゲッターがあると仮定して、メソッドを探してgetNameそれを呼び出します。

えっと、ちょうどこの答えを見た。それは私のものと同じです。私の実装についてのご意見をお聞かせください。
jjnguy

5

これを実行する式言語の実装がいくつかあります。独自の実装を使用するよりも、または要件が増えた場合に適しています。たとえば、JUELMVELを参照してください。

少なくとも1つのプロジェクトでMVELを気に入って使用してきました。

また、JSP(スタンドアロン)以外のコンテキストで StackflowポストJSTL / JSP EL(式言語)を参照してください。


0

速度はその問題を正確に解決するために記述されているので、速度に匹敵するものは何もありません。あなたが試すことができる最も近いことはフォーマッタを調べることです

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

ただし、私が知る限り、フォーマッターは、JavaでCのようなフォーマットオプションを提供するために作成されたため、かゆみを正確に解消することはできませんが、:)を試してみてください。


0

JavaでGroovyShellを使用して、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);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.