【问题标题】:Java equivalent of Python's format()Java 等价于 Python 的 format()
【发布时间】:2011-03-16 10:30:47
【问题描述】:

这里有两种进行字符串替换的方法:

name = "Tshepang"
"my name is {}".format(name)
"my name is " + name

如何使用 Java 执行类似于第一种方法的操作?

【问题讨论】:

    标签: java string


    【解决方案1】:
    name = "Paŭlo";
    MessageFormat f = new MessageFormat("my name is {0}");
    f.format(new Object[]{name});
    

    或更短:

    MessageFormat.format("my name is {0}", name);
    

    【讨论】:

      【解决方案2】:
      String s = String.format("something %s","name");
      

      【讨论】:

      • 有没有办法避免指定类型(例如%s),因为Python的format()函数允许?
      • @Tshepang 不幸的是,您不能将它与 python 中的文字一起使用。所以你总是需要在 String 类上调用这个静态方法。
      • @Chris:不确定你(或我)是否理解。我的意思是我会有类似于String.format("my name is {}", name) 的东西。
      • @Tshepang 可能值得看看 Formatter 类的 Java API,link
      • %s 说明符没有指定参数是字符串,但请像字符串一样格式化参数。如果参数实现Formattable,它调用它的formatTo 方法,否则它的toString 方法。因此它适用于任何对象,也适用于数字。
      【解决方案3】:

      Underscore-java 有一个 format() 静态方法。 Live example

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

      【讨论】:

        【解决方案4】:

        你可以试试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)
        

        【讨论】:

          猜你喜欢
          • 2012-11-18
          • 2013-11-24
          • 2010-11-23
          • 2012-06-28
          • 2021-09-15
          • 1970-01-01
          • 1970-01-01
          • 2010-12-05
          相关资源
          最近更新 更多