当前位置:  开发笔记 > 编程语言 > 正文

如何替换Java String中的一组标记?

如何解决《如何替换JavaString中的一组标记?》经验,为你挑选了8个好方法。

我有以下模板字符串:"Hello [Name] Please find attached [Invoice Number] which is due on [Due Date]".

我还有名称,发票号和截止日期的字符串变量 - 用变量替换模板中的标记的最佳方法是什么?

(请注意,如果变量恰好包含令牌,则不应替换它).


编辑

感谢@laginimaineb和@ alan-moore,这是我的解决方案:

public static String replaceTokens(String text, 
                                   Map 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();
}

Paul Morie.. 103

我真的认为你不需要使用模板引擎或类似的东西.您可以使用此String.format方法,如下所示:

String template = "Hello %s Please find attached %s which is due on %s";

String message = String.format(template, name, invoiceNumber, dueDate);

这样做的一个缺点是你必须按正确的顺序放置参数 (4认同)


laginimaineb.. 65

最有效的方法是使用匹配器不断查找表达式并替换它们,然后将文本附加到字符串构建器:

Pattern pattern = Pattern.compile("\\[(.+?)\\]");
Matcher matcher = pattern.matcher(text);
HashMap replacements = new HashMap();
//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();

我就是这样做的,除了我会使用Matcher的appendReplacement()和appendTail()方法来复制不匹配的文本; 没有必要手工完成. (10认同)

实际上,appendReplacement()和appentTail()方法需要一个StringBuffer,它是snychronized(在这里没用).给出的答案使用StringBuilder,在我的测试中速度提高了20%. (5认同)


小智.. 42

不幸的是,上面提到的舒适方法String.format只能从Java 1.5开始提供(现在应该是非常标准的,但你永远不知道).除此之外,您还可以使用Java的类MessageFormat来替换占位符.

它支持"{number}"形式的占位符,因此您的消息看起来像"Hello {0}请找到{2}到期的附件{1}".这些字符串可以使用ResourceBundles轻松外部化(例如,用于具有多个语言环境的本地化).替换将使用MessageFormat类的static'format'方法完成:

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

我记不起MessageFormat的名字了,有点傻傻的谷歌搜索我甚至要找到这个答案.每个人都表现得像String.format或使用第三方,忘记了这个非常有用的实用程序. (3认同)


hallidave.. 41

您可以尝试使用像Apache Velocity这样的模板库.

http://velocity.apache.org/

这是一个例子:

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

输出将是:

Hello Mark. Please find attached invoice 42123 which is due on June 6, 2009.

将整个库用于这样的简单任务有点过分.Velocity还有很多其他功能,我坚信这不适合这样的简单任务. (6认同)

同意,为什么重新发明轮子 (4认同)


Li Ying.. 24

您可以使用模板库进行复杂模板替换.

FreeMarker是一个非常好的选择.

http://freemarker.sourceforge.net/

但是对于简单的任务,有一个简单的实用类可以帮助你.

org.apache.commons.lang3.text.StrSubstitutor

它功能强大,可定制且易于使用.

该类接受一段文本并替换其中的所有变量.变量的默认定义是$ {variableName}.可以通过构造函数和set方法更改前缀和后缀.

变量值通常从映射中解析,但也可以从系统属性中解析,或者通过提供自定义变量解析器来解析.

例如,如果要将系统环境变量替换为模板字符串,则代码如下:

public class SysEnvSubstitutor {
    public static final String replace(final String source) {
        StrSubstitutor strSubstitutor = new StrSubstitutor(
                new StrLookup() {
                    @Override
                    public String lookup(final String key) {
                        return System.getenv(key);
                    }
                });
        return strSubstitutor.replace(source);
    }
}

org.apache.commons.lang3.text.StrSubstitutor对我很有用 (2认同)


小智.. 16

System.out.println(MessageFormat.format("Hello {0}! You have {1} messages", "Join",10L));

输出: 你好加入!你有10条消息"



1> Paul Morie..:

我真的认为你不需要使用模板引擎或类似的东西.您可以使用此String.format方法,如下所示:

String template = "Hello %s Please find attached %s which is due on %s";

String message = String.format(template, name, invoiceNumber, dueDate);


这样做的一个缺点是你必须按正确的顺序放置参数

2> laginimaineb..:

最有效的方法是使用匹配器不断查找表达式并替换它们,然后将文本附加到字符串构建器:

Pattern pattern = Pattern.compile("\\[(.+?)\\]");
Matcher matcher = pattern.matcher(text);
HashMap replacements = new HashMap();
//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();


我就是这样做的,除了我会使用Matcher的appendReplacement()和appendTail()方法来复制不匹配的文本; 没有必要手工完成.
实际上,appendReplacement()和appentTail()方法需要一个StringBuffer,它是snychronized(在这里没用).给出的答案使用StringBuilder,在我的测试中速度提高了20%.

3> 小智..:

不幸的是,上面提到的舒适方法String.format只能从Java 1.5开始提供(现在应该是非常标准的,但你永远不知道).除此之外,您还可以使用Java的类MessageFormat来替换占位符.

它支持"{number}"形式的占位符,因此您的消息看起来像"Hello {0}请找到{2}到期的附件{1}".这些字符串可以使用ResourceBundles轻松外部化(例如,用于具有多个语言环境的本地化).替换将使用MessageFormat类的static'format'方法完成:

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


我记不起MessageFormat的名字了,有点傻傻的谷歌搜索我甚至要找到这个答案.每个人都表现得像String.format或使用第三方,忘记了这个非常有用的实用程序.

4> hallidave..:

您可以尝试使用像Apache Velocity这样的模板库.

http://velocity.apache.org/

这是一个例子:

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

输出将是:

Hello Mark. Please find attached invoice 42123 which is due on June 6, 2009.


将整个库用于这样的简单任务有点过分.Velocity还有很多其他功能,我坚信这不适合这样的简单任务.
同意,为什么重新发明轮子

5> Li Ying..:

您可以使用模板库进行复杂模板替换.

FreeMarker是一个非常好的选择.

http://freemarker.sourceforge.net/

但是对于简单的任务,有一个简单的实用类可以帮助你.

org.apache.commons.lang3.text.StrSubstitutor

它功能强大,可定制且易于使用.

该类接受一段文本并替换其中的所有变量.变量的默认定义是$ {variableName}.可以通过构造函数和set方法更改前缀和后缀.

变量值通常从映射中解析,但也可以从系统属性中解析,或者通过提供自定义变量解析器来解析.

例如,如果要将系统环境变量替换为模板字符串,则代码如下:

public class SysEnvSubstitutor {
    public static final String replace(final String source) {
        StrSubstitutor strSubstitutor = new StrSubstitutor(
                new StrLookup() {
                    @Override
                    public String lookup(final String key) {
                        return System.getenv(key);
                    }
                });
        return strSubstitutor.replace(source);
    }
}


org.apache.commons.lang3.text.StrSubstitutor对我很有用

6> 小智..:
System.out.println(MessageFormat.format("Hello {0}! You have {1} messages", "Join",10L));

输出: 你好加入!你有10条消息"


约翰清楚地检查了他的邮件,就像我检查我的“垃圾邮件”文件夹一样,因为它很长。

7> Bruno Ransch..:
String.format("Hello %s Please find attached %s which is due on %s", name, invoice, date)



8> Ricardo Mari..:

它取决于您要替换的实际数据的位置.你可能有这样的地图:

Map values = new HashMap();

包含可以替换的所有数据.然后,您可以迭代地图并更改String中的所有内容,如下所示:

String s = "Your String with [Fields]";
for (Map.Entry e : values.entrySet()) {
  s = s.replaceAll("\\[" + e.getKey() + "\\]", e.getValue());
}

您还可以遍历String并在地图中查找元素.但这有点复杂,因为你需要解析String搜索[].你可以使用Pattern和Matcher使用正则表达式来完成它.

推荐阅读
贾志军
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有