如何使用参数名称而不是数字来格式化消息?

问题描述 投票:0回答:7

我有类似的东西:

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

这对我来说不太好,因为有时我的翻译人员不确定 {0} 和 {1} 中的内容,而且如果能够重写消息而不必担心参数的顺序,那就太好了。

我想用可读的名称而不是数字替换参数。像这样的东西:

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

有没有简单的方法可以做到这一点?

谢谢! 抢

java string-formatting
7个回答
35
投票

您可以使用

MapFormat
来实现此目的。在这里了解详细信息:

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

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

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

输出:

第一:用户 Robert 的电子邮件地址为 [email protected]


24
投票

参见org.apache.commons.lang3中的

StrSubstitutor

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."

10
投票

自己制作一个很容易。这就是我使用的(

main()
函数仅用于测试代码):

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

1
投票

您的问题与以下内容密切相关:如何替换 Java 字符串中的一组标记 您可以使用 velocity 或其他模板库。但会有一些痛苦,因为 Java 没有任何类型的 Map 文字。


1
投票

我知道我的答案来得有点晚了,但如果你仍然需要这个功能,而不需要下载成熟的模板引擎,你可以看看aleph-formatter(我是作者之一):

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 通过“解析”表达式创建结果,不执行字符串连接、正则表达式/替换。


0
投票
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;
}

但是您失去了所有格式选项(例如##.#)


0
投票

如果不需要使用地图,那么您可以使用 Java 的字符串模板功能。 它在 JEP 430 中进行了描述,并作为预览功能出现在 JDK 21 中。这是一个使用示例:

String username = "rtm";
String emailaddress = "[email protected]";
String text = STR."The user \{username} has email address \{emailaddress}."

Java 的字符串模板比其他语言(例如 C# 的字符串插值和 Python 的 f 字符串)中的功能更通用,也更安全。 例如,字符串连接或插值使得 SQL 注入攻击成为可能:

String query = "SELECT * FROM Person p WHERE p.last_name = '" + name + "'";
ResultSet rs = conn.createStatement().executeQuery(query);

但是这个变体(来自 JEP 430)可以防止 SQL 注入:

PreparedStatement ps = DB."SELECT * FROM Person p WHERE p.last_name = \{name}";
ResultSet rs = ps.executeQuery();
© www.soinside.com 2019 - 2024. All rights reserved.