如何替换 Java 字符串中的一组标记?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/959731/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to replace a set of tokens in a Java String?
提问by Mark
I have the following template String: "Hello [Name] Please find attached [Invoice Number] which is due on [Due Date]"
.
我有以下模板字符串:"Hello [Name] Please find attached [Invoice Number] which is due on [Due Date]"
.
I also have String variables for name, invoice number and due date - what's the best way to replace the tokens in the template with the variables?
我还有名称、发票号和到期日的字符串变量 - 用变量替换模板中的令牌的最佳方法是什么?
(Note that if a variable happens to contain a token it should NOT be replaced).
(请注意,如果变量恰好包含一个标记,则不应替换它)。
EDIT
编辑
With thanks to @laginimaineb and @alan-moore, here's my solution:
感谢@laginimaineb 和@alan-moore,这是我的解决方案:
public static String replaceTokens(String text,
Map<String, String> replacements) {
Pattern pattern = Pattern.compile("\[(.+?)\]");
Matcher matcher = pattern.matcher(text);
StringBuffer buffer = new StringBuffer();
while (matcher.find()) {
String replacement = replacements.get(matcher.group(1));
if (replacement != null) {
// matcher.appendReplacement(buffer, replacement);
// see comment
matcher.appendReplacement(buffer, "");
buffer.append(replacement);
}
}
matcher.appendTail(buffer);
return buffer.toString();
}
采纳答案by laginimaineb
The most efficient way would be using a matcher to continually find the expressions and replace them, then append the text to a string builder:
最有效的方法是使用匹配器不断查找表达式并替换它们,然后将文本附加到字符串构建器:
Pattern pattern = Pattern.compile("\[(.+?)\]");
Matcher matcher = pattern.matcher(text);
HashMap<String,String> replacements = new HashMap<String,String>();
//populate the replacements map ...
StringBuilder builder = new StringBuilder();
int i = 0;
while (matcher.find()) {
String replacement = replacements.get(matcher.group(1));
builder.append(text.substring(i, matcher.start()));
if (replacement == null)
builder.append(matcher.group(0));
else
builder.append(replacement);
i = matcher.end();
}
builder.append(text.substring(i, text.length()));
return builder.toString();
回答by hallidave
You could try using a templating library like Apache Velocity.
您可以尝试使用像 Apache Velocity 这样的模板库。
Here is an example:
下面是一个例子:
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import java.io.StringWriter;
public class TemplateExample {
public static void main(String args[]) throws Exception {
Velocity.init();
VelocityContext context = new VelocityContext();
context.put("name", "Mark");
context.put("invoiceNumber", "42123");
context.put("dueDate", "June 6, 2009");
String template = "Hello $name. Please find attached invoice" +
" $invoiceNumber which is due on $dueDate.";
StringWriter writer = new StringWriter();
Velocity.evaluate(context, writer, "TemplateName", template);
System.out.println(writer);
}
}
The output would be:
输出将是:
Hello Mark. Please find attached invoice 42123 which is due on June 6, 2009.
回答by Ricardo Marimon
It depends of where the actual data that you want to replace is located. You might have a Map like this:
这取决于您要替换的实际数据所在的位置。你可能有这样的地图:
Map<String, String> values = new HashMap<String, String>();
containing all the data that can be replaced. Then you can iterate over the map and change everything in the String as follows:
包含所有可以替换的数据。然后您可以遍历地图并更改字符串中的所有内容,如下所示:
String s = "Your String with [Fields]";
for (Map.Entry<String, String> e : values.entrySet()) {
s = s.replaceAll("\[" + e.getKey() + "\]", e.getValue());
}
You could also iterate over the String and find the elements in the map. But that is a little bit more complicated because you need to parse the String searching for the []. You could do it with a regular expression using Pattern and Matcher.
您还可以遍历 String 并在地图中查找元素。但这有点复杂,因为您需要解析搜索 [] 的字符串。您可以使用 Pattern 和 Matcher 使用正则表达式来完成。
回答by Bruno Ranschaert
String.format("Hello %s Please find attached %s which is due on %s", name, invoice, date)
回答by Paul Morie
I really don't think you need to use a templating engine or anything like that for this. You can use the String.format
method, like so:
我真的不认为你需要为此使用模板引擎或类似的东西。您可以使用该String.format
方法,如下所示:
String template = "Hello %s Please find attached %s which is due on %s";
String message = String.format(template, name, invoiceNumber, dueDate);
回答by laginimaineb
Unfortunately the comfortable method String.format mentioned above is only available starting with Java 1.5 (which should be pretty standard nowadays, but you never know). Instead of that you might also use Java's class MessageFormatfor replacing the placeholders.
不幸的是,上面提到的舒适方法 String.format 仅从 Java 1.5 开始可用(现在应该是非常标准的,但你永远不知道)。取而代之的是,您还可以使用 Java 的MessageFormat 类来替换占位符。
It supports placeholders in the form '{number}', so your message would look like "Hello {0} Please find attached {1} which is due on {2}". These Strings can easily be externalized using ResourceBundles (e. g. for localization with multiple locales). The replacing would be done using the static'format' method of class MessageFormat:
它支持“{number}”形式的占位符,因此您的消息看起来像“你好{0}请找到附件的{1},它将于{2}到期”。这些字符串可以使用 ResourceBundles 轻松地外部化(例如,用于具有多个语言环境的本地化)。替换将使用类 MessageFormat 的静态“格式”方法完成:
String msg = "Hello {0} Please find attached {1} which is due on {2}";
String[] values = {
"John Doe", "invoice #123", "2009-06-30"
};
System.out.println(MessageFormat.format(msg, values));
回答by Francois Gravel
In the past, I've solved this kind of problem with StringTemplateand Groovy Templates.
过去,我用StringTemplate和Groovy Templates解决了这类问题。
Ultimately, the decision of using a templating engine or not should be based on the following factors:
最终,是否使用模板引擎的决定应基于以下因素:
- Will you have many of these templates in the application?
- Do you need the ability to modify the templates without restarting the application?
- Who will be maintaining these templates? A Java programmer or a business analyst involved on the project?
- Will you need to the ability to put logic in your templates, like conditional text based on values in the variables?
- Will you need the ability to include other templates in a template?
- 您的应用程序中会有很多这样的模板吗?
- 您是否需要能够在不重新启动应用程序的情况下修改模板?
- 谁来维护这些模板?参与该项目的 Java 程序员或业务分析师?
- 您是否需要能够将逻辑放入模板中,例如基于变量中的值的条件文本?
- 您是否需要能够在模板中包含其他模板?
If any of the above applies to your project, I would consider using a templating engine, most of which provide this functionality, and more.
如果上述任何一项适用于您的项目,我会考虑使用模板引擎,其中大多数提供此功能,等等。
回答by mtwom
I used
我用了
String template = "Hello %s Please find attached %s which is due on %s";
String message = String.format(template, name, invoiceNumber, dueDate);
回答by Li Ying
You can use template library for complex template replacement.
您可以使用模板库进行复杂的模板替换。
FreeMarker is a very good choice.
FreeMarker 是一个非常好的选择。
http://freemarker.sourceforge.net/
http://freemarker.sourceforge.net/
But for simple task, there is a simple utility class can help you.
但是对于简单的任务,有一个简单的实用程序类可以帮助您。
org.apache.commons.lang3.text.StrSubstitutor
org.apache.commons.lang3.text.StrSubstitutor
It is very powerful, customizable, and easy to use.
它非常强大、可定制且易于使用。
This class takes a piece of text and substitutes all the variables within it. The default definition of a variable is ${variableName}. The prefix and suffix can be changed via constructors and set methods.
Variable values are typically resolved from a map, but could also be resolved from system properties, or by supplying a custom variable resolver.
该类采用一段文本并替换其中的所有变量。变量的默认定义是 ${variableName}。可以通过构造函数和 set 方法更改前缀和后缀。
变量值通常从映射解析,但也可以从系统属性解析,或通过提供自定义变量解析器。
For example, if you want to substitute system environment variable into a template string, here is the code:
例如,如果要将系统环境变量替换为模板字符串,则代码如下:
public class SysEnvSubstitutor {
public static final String replace(final String source) {
StrSubstitutor strSubstitutor = new StrSubstitutor(
new StrLookup<Object>() {
@Override
public String lookup(final String key) {
return System.getenv(key);
}
});
return strSubstitutor.replace(source);
}
}