10

のようなものの標準的な、または少なくとも広く普及している実装はありますString.formatが、名前付きの引数がありますか?

テンプレート化された文字列を次のようにフォーマットしたいと思います。

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

技術的には、次のようになります。

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

しかし、名前付きの引数を使用します。

私は知っています:

しかし、それらはすべて、名前付きの引数ではなく、順序付きまたは少なくとも番号付きの引数を使用します。実装するのは簡単ですが、注目を集めるテンプレートエンジンを導入せずに、標準のJavaライブラリまたは少なくともApache Commons / Guava /類似のもので探しているメカニズムはありますか?

:命令型/機能ロジック、フロー制御、修飾子、サブテンプレート/インクルージョン、イテレーターなどの機能を備えた本格的なテンプレートエンジンにはあまり興味がありません。通常、次の方法は4行の実装です。 - それが私が必要なものすべてです:

public static String interpolate(String format, Map<String, ? extends Object> args) {
    String out = format;
    for (String arg : args.keySet()) {
        out = Pattern.compile(Pattern.quote("#{" + arg + "}")).
                matcher(out).
                replaceAll(args.get(arg).toString());
    }
    return out;
}
4

7 に答える 7

10

org.apache.commons.lang3.text.StrSubstitutorJava7がオプションでない場合も試してみてください。それはあなたがしたいことを正確に行います。軽量かどうかは、他のcommons-langを使用するかどうかによって異なります。

于 2012-07-13T11:24:26.427 に答える
4

Matcher#appendReplacement()が役立ちます

于 2012-06-29T15:29:28.027 に答える
3

私は最近、説明にぴったり合うJUELを発見しました。これは、JSPから取り出された表現言語です。それも非常に速いと主張しています。

私は自分のプロジェクトの1つでそれを試してみようとしています。

しかし、あなたのバリエーションである軽量の場合は、これを試してください(単体テストでラップされています):

public class TestInterpolation {

    public static class NamedFormatter {
        public final static Pattern pattern = Pattern.compile("#\\{(?<key>.*)}");
        public static String format(final String format, Map<String, ? extends Object> kvs) {
            final StringBuffer buffer = new StringBuffer();
            final Matcher match = pattern.matcher(format);
            while (match.find()) {
                final String key = match.group("key");
                final Object value = kvs.get(key);
                if (value != null)
                    match.appendReplacement(buffer, value.toString());
                else if (kvs.containsKey(key))
                    match.appendReplacement(buffer, "null");
                else
                    match.appendReplacement(buffer, "");
            }
            match.appendTail(buffer);
            return buffer.toString();
        }
    }

    @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<String, Object>()));
    }

    private Map<String, Object> map(final String key, final Object value) {
        final Map<String, Object> kvs = new HashMap<>();
        kvs.put(key, value);
        return kvs;
    }
}

これを拡張して、便利なメソッドを追加し、キーと値のペアをすばやく作成します

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

そして、Java7+からJava6-に変換するのはそれほど難しいことではありません。

于 2012-10-21T08:14:16.350 に答える
2

StringTemplateは、 FreeMarkerMustacheVelocityなどに対してリソース的にどのようにスタックするかはわかりませんが、入手する可能性が高いほど軽量の補間エンジンである可能性があります。

別のオプションは、テンプレートエンジンを備えたMVELのようなELエンジンである可能性があります。

于 2012-06-29T15:07:49.550 に答える
0

これが私の解決策です:

public class Template
{

    private Pattern pattern;
    protected Map<CharSequence, String> tokens;
    private String template;

    public Template(String template)
    {
        pattern = Pattern.compile("\\$\\{\\w+\\}");
        tokens = new HashMap<CharSequence, String>();
        this.template = template;
    }

    public void clearAllTokens()
    {
        tokens.clear();
    }

    public void setToken(String token, String replacement)
    {
        if(token == null)
        {
            throw new NullPointerException("Token can't be null");
        }

        if(replacement == null)
        {
            throw new NullPointerException("Replacement string can't be null");
        }

        tokens.put(token, Matcher.quoteReplacement(replacement));
    }

    public String getText()
    {
        final Matcher matcher = pattern.matcher(template);
        final StringBuffer sb = new StringBuffer();

        while(matcher.find()) 
        {
            final String 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.toString();
    }


    public static void main(String[] args) {
        Template template = new Template("Hello, ${name}.");
        template.setToken("name", "Eldar");

        System.out.println(template.getText());
    }
}
于 2015-12-04T06:37:19.903 に答える
0

私の答えは少し遅れていることは知っていますが、それでもこの機能が必要な場合は、本格的なテンプレートエンジンをダウンロードする必要がなく、aleph-formatterを見ることができます(私は著者の1人です):

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

または、引数を連鎖させることができます。

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

// Output: "5 + 10 = 15"

内部的には、StringBuilderを使用して機能し、式を「解析」して結果を作成します。文字列の連結は行われず、正規表現/置換は実行されません。

于 2017-03-29T19:56:20.783 に答える
0

また、str utils(テストされていません)で作成しstring.MapFormat("abcd {var}",map)ました。

//util
public static String mapFormat(String template, HashMap<String, String> mapSet) {
    String res = template;
    for (String key : mapSet.keySet()) {
        res = template.replace(String.format("{%s}", key), mapSet.get(key));
    }
    return res;
}

//use

public static void main(String[] args) {
    boolean isOn=false;
    HashMap<String, String> kvMap=new HashMap<String, String>();
    kvMap.put("isOn", isOn+"");
    String exp=StringUtils.mapFormat("http://localhost/api/go?isOn={isOn}", kvMap);
    System.out.println(exp);
}
于 2019-11-05T14:54:18.617 に答える