以下是两种字符串替换的方法:
name = "Tshepang"
"my name is {}".format(name)
"my name is " + name
我该如何使用Java实现类似于第一种方法的功能?
name = "Paŭlo";
MessageFormat f = new MessageFormat("my name is {0}");
f.format(new Object[]{name});
或者更短:
MessageFormat.format("my name is {0}", name);
String s = String.format("something %s","name");
Underscore-java有一个名为format()
的静态方法。点击此处查看实例
import com.github.underscore.Underscore;
public class Main {
public static void main(String[] args) {
String name = "Tshepang";
String formatted = Underscore.format("my name is {}", name);
// my name is Tshepang
}
}
你可以尝试this
package template.fstyle;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static java.util.Objects.nonNull;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class FStyleFinal {
private static final String PLACEHOLDERS_KEY = "placeholders";
private static final String VARIABLE_NAMES_KEY = "variableNames";
private static final String PLACEHOLDER_PREFIX = "{{";
private static final String PLACEHOLDER_SUFFIX = "}}";
private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\{\\{\\s*([\\S]+)\\s*}}");
private static Map<String, List<String>> toPlaceholdersAndVariableNames(String rawTemplate) {
List<String> placeholders = newArrayList();
List<String> variableNames = newArrayList();
Matcher matcher = PLACEHOLDER_PATTERN.matcher(rawTemplate);
while (matcher.find()) {
for (int j = 0; j <= matcher.groupCount(); j++) {
String s = matcher.group(j);
if (StringUtils.startsWith(s, PLACEHOLDER_PREFIX) && StringUtils.endsWith(s, PLACEHOLDER_SUFFIX)) {
placeholders.add(s);
} else if (!StringUtils.startsWith(s, PLACEHOLDER_PREFIX) && !StringUtils.endsWith(s, PLACEHOLDER_SUFFIX)) {
variableNames.add(s);
}
}
}
checkArgument(CollectionUtils.size(placeholders) == CollectionUtils.size(variableNames), "template engine error");
Map<String, List<String>> map = newHashMap();
map.put(PLACEHOLDERS_KEY, placeholders);
map.put(VARIABLE_NAMES_KEY, variableNames);
return map;
}
private static String toJavaTemplate(String rawTemplate, List<String> placeholders) {
String javaTemplate = rawTemplate;
for (String placeholder : placeholders) {
javaTemplate = StringUtils.replaceOnce(javaTemplate, placeholder, "%s");
}
return javaTemplate;
}
private static Object[] toJavaTemplateRenderValues(Map<String, String> context, List<String> variableNames, boolean allowNull) {
return variableNames.stream().map(name -> {
String value = context.get(name);
if (!allowNull) {
checkArgument(nonNull(value), name + " should not be null");
}
return value;
}).toArray();
}
private static Map<String, String> fromBeanToMap(Object bean, List<String> variableNames) {
return variableNames.stream().distinct().map(name -> {
String value = null;
try {
value = BeanUtils.getProperty(bean, name);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
log.debug("fromBeanToMap error", e);
}
return Pair.of(name, value);
}).filter(p -> nonNull(p.getRight())).collect(Collectors.toMap(Pair::getLeft, Pair::getRight));
}
public static String render(String rawTemplate, Map<String, String> context, boolean allowNull) {
Map<String, List<String>> templateMeta = toPlaceholdersAndVariableNames(rawTemplate);
List<String> placeholders = templateMeta.get(PLACEHOLDERS_KEY);
List<String> variableNames = templateMeta.get(VARIABLE_NAMES_KEY);
// transform template to java style template
String javaTemplate = toJavaTemplate(rawTemplate, placeholders);
Object[] renderValues = toJavaTemplateRenderValues(context, variableNames, allowNull);
return String.format(javaTemplate, renderValues);
}
public static String render(String rawTemplate, Object bean, boolean allowNull) {
Map<String, List<String>> templateMeta = toPlaceholdersAndVariableNames(rawTemplate);
List<String> variableNames = templateMeta.get(VARIABLE_NAMES_KEY);
Map<String, String> mapContext = fromBeanToMap(bean, variableNames);
return render(rawTemplate, mapContext, allowNull);
}
public static void main(String[] args) {
String template = "hello, my name is {{ name }}, and I am {{age}} years old, a null value {{ not_exists }}";
Map<String, String> context = newHashMap();
context.put("name", "felix");
context.put("age", "18");
String s = render(template, context, true);
log.info("{}", s);
try {
render(template, context, false);
} catch (IllegalArgumentException e) {
log.error("error", e);
}
}
}
示例输出:
[main] INFO template.fstyle.FStyleFinal - hello, my name is felix, and I am 18 years old, a null value null
[main] ERROR template.fstyle.FStyleFinal - error
java.lang.IllegalArgumentException: not_exists should not be null
at com.google.common.base.Preconditions.checkArgument(Preconditions.java:142)
at template.fstyle.FStyleFinal.lambda$toJavaTemplateRenderValues$0(FStyleFinal.java:69)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:545)
at java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260)
at java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:438)
at java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:444)
at template.fstyle.FStyleFinal.toJavaTemplateRenderValues(FStyleFinal.java:72)
at template.fstyle.FStyleFinal.render(FStyleFinal.java:93)
at template.fstyle.FStyleFinal.main(FStyleFinal.java:113)
%s
),就像Python的format()
函数一样? - tshepangString.format("我的名字是 {}", name)
这样的东西。 - tshepang%s
占位符并不表示参数是一个字符串,而是要求将参数格式化为字符串。如果参数实现了Formattable
接口,则调用其formatTo
方法,否则调用其toString
方法。因此,它可以用于任何对象,包括数字。 - Paŭlo Ebermann