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

发布于 2024-10-27 14:17:33 字数 818 浏览 0 评论 0原文

我有这样的想法:

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

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

谢谢! 抢

I have something like:

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

This isn't great for me, because sometimes my translators are not sure what goes in the {0} and {1}, also it would be nice to be able to reword the messages without worrying about the order of the args.

I'd like to replace the arguments with readable names instead of numbers. Something like this:

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

Is there an easy way to do this?

Thanks!
rob

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

泪是无色的血 2024-11-03 14:17:33

您可以使用 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 的电子邮件地址[电子邮件受保护]

You can use MapFormat for this. Find out the details here:

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

OUTPUT:

1st : The user Robert has email address [email protected].

夏有森光若流苏 2024-11-03 14:17:33

请参阅 StrSubstitutor< /a> 来自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."

See StrSubstitutor from 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."
☆獨立☆ 2024-11-03 14:17:33

自己制作一个很容易。这就是我使用的( 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));
    }
}

Easy to make one yourself. This is what I use (the main() function is just for test code):

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));
    }
}
泪是无色的血 2024-11-03 14:17:33

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

Your question is closely related to: How to replace a set of tokens in a Java String
You could use velocity or another template library. But there will be some pain because Java does not have any kind of Map literals.

枉心 2024-11-03 14:17:33

我知道我的回答有点晚了,但如果您仍然需要此功能,而不需要下载成熟的模板引擎,您可以看看 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 通过“解析”表达式创建结果,不字符串连接、正则表达式/替换被执行。

I know my answer comes a little late, but if you still need this functionality, without the need to download a full-fledged template engine you can take a look at aleph-formatter (I am one of the authors):

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

Or you can chain the arguments:

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

// Output: "5 + 10 = 15"

Internally it works using a StringBuilder creating the result by "parsing" the expression, no string concatenation, regex/replace is performed.

要走就滚别墨迹 2024-11-03 14:17:33

如果不需要使用映射,那么您可以使用 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();

If use of a map is not a requirement, then you can use Java's String Templates feature.
It is described in JEP 430, and it appears in JDK 21 as a preview feature. Here is an example use:

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

Java's string templates are more versatile, and much safer, than features in other languagues such as C#'s string interpolation and Python's f-strings.
For example, string concatenation or interpolation makes SQL injection attacks possible:

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

but this variant (from JEP 430) prevents SQL injection:

PreparedStatement ps = DB."SELECT * FROM Person p WHERE p.last_name = \{name}";
ResultSet rs = ps.executeQuery();
硬不硬你别怂 2024-11-03 14:17:33
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;
}

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

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

But you loose all format options (like ##.#)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文