代码之家  ›  专栏  ›  技术社区  ›  Jason R. Coombs

使用类属性在Java中格式化字符串

  •  4
  • Jason R. Coombs  · 技术社区  · 15 年前

    我有一个具有属性和getter方法的类:

    public Class MyClass
    {
      private String myValue = "foo";
    
      public String getMyValue();
    }
    

    我希望能够在格式化字符串中使用foo的值,例如:

    String someString = "Your value is {myValue}."
    String result = Formatter.format(someString, new MyClass());
    // result is now "Your value is foo."
    

    也就是说,我想要一些功能 .format 上面是一个格式字符串,指定一些对象的属性,以及一个具有这些属性的实例,并相应地格式化字符串。

    在Java中实现这一壮举是可能的吗?

    4 回复  |  直到 15 年前
        1
  •  3
  •   Stefan De Boey    15 年前

    你可以用 JUEL 为此。它是Java表达式语言的一个实现。代码相当紧凑,如下所示:

    ExpressionFactory factory = new ExpressionFactoryImpl();
    
    // create a context and add a Person object to the context, this variable will be used
    // in the property replacement
    // objects of type Person have two fields: firstName and lastName
    
    SimpleContext context = new SimpleContext();
    Person person = new Person("John", "Doe");
    context.setVariable("person", factory.createValueExpression(person, Person.class));
    
    // create the expression
    
    String expr = "My name is ${person.firstName} ${person.lastName}";
    ValueExpression e = factory.createValueExpression(context, expr, String.class);
    
    // evaluate the expression
    System.out.println(e.getValue(context));
    

    上面印着“我叫约翰·多伊”

    请注意,也可以使用类似这样的表达式:“$firstname”而不是“$person.firstname”,但是您必须为变量和属性解析编写并提供自定义冲突解决程序(javax.el.el resolver)。

        2
  •  2
  •   Stephen Denne    15 年前

    (我的另一个答案可能只有在您已经使用Struts的情况下才有用。)

    与SDB的答案类似,有 apache JEXL .

    这个 UnifiedJEXL 类提供类似模板的功能,因此您可以编写( as shown in javadocs ):

    JexlEngine jexl = new JexlEngine();
    UnifiedJEXL ujexl = new UnifiedJEXL(jexl);
    UnifiedJEXL.Expression expr = ujexl.parse("Hello ${user}");
    String hello = expr.evaluate(context, expr).toString();
    

    (The expr 不仅作为参数传递给方法本身看起来很奇怪,而且确实不需要作为参数)

    上下文设置显示在同一页的前面:

    // Create a context and add data
    JexlContext jc = new MapContext();
    jc.set("foo", new Foo() );
    

    您还需要共享日志记录,或者可以配置jexl使用自己的日志记录程序。


    为了接近你的要求,你可以创建:

    public class Formatter {
        public static String format(String format, Object ... inputs) {
            JexlContext context = new MapContext();
            for (int i=0;i<inputs.length;i++) {
                context.set("_" + (i+1), inputs[i] );
            }
            JexlEngine jexl = new JexlEngine();
            UnifiedJEXL ujexl = new UnifiedJEXL(jexl);
            UnifiedJEXL.Expression expr = ujexl.parse(format);
            return expr.evaluate(context).toString();
        }
    }
    

    然后打电话给

    String someString = "Your value is ${_1.myValue}.";
    String result = Formatter.format(someString, new MyClass());
    

    在这一点上, result "Your value is foo."

        3
  •  0
  •   BalusC    15 年前

    理论上,使用基于堆栈的解析器可以结合 reflection (或者更好的是,JavaBean检查API,例如 Commons BeanUtils )获取bean属性值。

    不幸的是,如果您正在寻找现成的或第三方的API,您不会想到。不过,这是一个有趣的问题。

        4
  •  0
  •   Stephen Denne    15 年前

    您可以使用struts2/xwork/ognl创建一个,类似于以下内容(复制自 an email from Vlad )

    public static String translateOgnl(String message, Map<Object, Object> args) {
        OgnlValueStack stack = new OgnlValueStack();
        stack.push(args);
        return TextParseUtil.translateVariables(message, stack);
    }
    

    用于 TextParseUtil.translateVariables()

    将表达式中的所有$…实例转换为调用返回的值 ValueStack.findValue(java.lang.String) . 如果在堆栈上找不到项(返回空值),则不会显示整个变量$…,就像该项在堆栈上但返回空字符串一样。