如何在Java中实现字符串格式化机制?

如何在Java中实现字符串格式化机制?,java,tokenize,Java,Tokenize,我正在尝试创建一个字符串格式化机制,它看起来很像 我将一些“变量”(或元数据字段)绑定到对象属性,形式为%varname%。因此,例如,%title%元数据字段绑定到歌曲标题,如“征服天堂”,%artist%元数据字段绑定到歌曲艺术家,如“Vangelis”,而%feat%元数据字段绑定到特色艺术家,如“English Chamber Choir” 现在,我想根据给定的格式显示歌曲,例如: %title%[ (by %artist%[ featuring %feat%])] 方括号表示除非设置

我正在尝试创建一个字符串格式化机制,它看起来很像

我将一些“变量”(或元数据字段)绑定到对象属性,形式为%varname%。因此,例如,%title%元数据字段绑定到歌曲标题,如“征服天堂”,%artist%元数据字段绑定到歌曲艺术家,如“Vangelis”,而%feat%元数据字段绑定到特色艺术家,如“English Chamber Choir”

现在,我想根据给定的格式显示歌曲,例如:

%title%[ (by %artist%[ featuring %feat%])]
方括号表示除非设置了括号内的(所有)元数据,否则不显示。方括号的嵌套应该是可能的。
因此,上面提到的格式化字符串表示:显示元数据字段%title%,如果设置了%artist%(非空字符串),则显示
(由%artist%)
,但如果%feat%元数据字段也非空,则也显示该字段。在上述示例中,它将变成:

征服天堂(由Vangelis主唱英国室内合唱团)

现在我该如何制作这样的机制?我从哪里开始


我想我必须对字符串进行标记,然后根据“部分”搜索元数据标记?

我将建立一个表示模式的树结构。例如,它看起来像:

root
 + variable (title)
 + group 
   + text (" (by ")
   + variable (artist)
   + group
     + text (" featuring ")
     + variable (feat)
   + text (")")
然后,当您根据树评估元数据时,您将在组级别存储是否评估了组中的所有变量和子组,如果是,则使用文本

您的树类看起来像:

interface Node { String evaluate(Map<String, String> metaData); }

class Group implements Node 
{
  private final List<Node> _children;

  Group(final List<Node> children) { _children = children; }

  @Override
  public String evaluate(final Map<String, String> metaData)
  {
    final StringBuilder sb = new StringBuilder(); 
    for (final Node node : _children)
    {
      final String subText = node.evaluate(metaData);
      if (subText == null)
        return null;
      sb.append(subText);
    }
    return sb.toString();
  }
}

class Text implements Node 
{
  private final String _text;

  Text(final String text) { _text = text; }

  @Override
  public String evaluate(final Map<String, String> metaData)
  {
    return _text;
  }
}

class Variable implements Node 
{
  private final String _variable;

  Variable(final String variable) { _variable = variable; }

  @Override
  public String evaluate(final Map<String, String> metaData)
  {
    return metaData.get(_variable);
  }
}
接口节点{字符串求值(映射元数据);}
类组实现节点
{
私人最终名单——儿童;
组(最终列表子项){u children=children;}
@凌驾
公共字符串求值(最终地图元数据)
{
最终StringBuilder sb=新StringBuilder();
对于(最终节点:\子节点)
{
最终字符串subText=node.evaluate(元数据);
if(subText==null)
返回null;
某人附加(潜台词);
}
使某人返回字符串();
}
}
类文本实现节点
{
私有最终字符串_文本;
文本(最终字符串文本){u Text=Text;}
@凌驾
公共字符串求值(最终地图元数据)
{
返回文本;
}
}
类变量实现节点
{
私有最终字符串_变量;
变量(最终字符串变量){u Variable=Variable;}
@凌驾
公共字符串求值(最终地图元数据)
{
返回metaData.get(_变量);
}
}
剩下要做的就是解决如何解析字符串以创建树结构。

基于of,我编写了一个标记器,执行建议的内容,将格式化字符串拆分为标记

public class Main {

    private static void buildTree(String format) {
        Stack<Token> st = new Stack<>();
        StringBuilder sb = new StringBuilder();
        GroupToken root = new GroupToken();
        st.push(root);

        boolean var = false;

        for (int i = 0; i < format.length(); i++) {
            char currentChar = format.charAt(i);
            switch (currentChar) {
                case '[':
                    String str = sb.toString();
                    sb.setLength(0); // Flush the StringBuilder
                    if (!str.equals("")) {
                        ((GroupToken) st.peek()).add(new TextToken(str));
                    }
                    GroupToken gt = new GroupToken();
                    ((GroupToken) st.peek()).add(gt);
                    st.push(gt);
                    break;
                case ']':
                    str = sb.toString();
                    sb.setLength(0); // Flush the StringBuilder
                    if (!str.equals("")) {
                        ((GroupToken) st.peek()).add(new TextToken(str));
                    }
                    st.pop();
                    break;
                case '%':
                    var = !var;
                    if (var) {
                        str = sb.toString();
                        sb.setLength(0); // Flush the StringBuilder
                        if (!str.equals("")) {
                            ((GroupToken) st.peek()).add(new TextToken(str));
                        }
                    }
                    else {
                        str = sb.toString();
                        sb.setLength(0); // Flush the StringBuilder
                        ((GroupToken) st.peek()).add(new VariableToken(str));
                    }
                    break;
                default:
                    sb.append(currentChar);
                    break;
            }
        }
        // Process the last remains of the string buffer...
        String str = sb.toString();
        sb.setLength(0); // Flush the StringBuilder
        if (!str.equals("")) {
            ((GroupToken) st.peek()).add(new TextToken(str));
        }
        st.pop();
        System.out.println(root);
    }

    public static void main(String[] arguments) throws Exception {
        buildTree("%title%[ (%alttitle%[, #%track%])]");
    }

}

abstract class Token {

    public abstract String toString(int indent);

}

class TextToken extends Token {

    private String text;

    public TextToken(String text) {
        this.text = text;
    }

    @Override
    public String toString() {
        return toString(0);
    }

    @Override
    public String toString(int indent) {
        return "TextToken[\"" + this.text + "\"]\n";
    }
}

class VariableToken extends Token {

    private String text;

    public VariableToken(String text) {
        this.text = text;
    }

    @Override
    public String toString() {
        return toString(0);
    }

    @Override
    public String toString(int indent) {
        return "VariableToken[\"" + this.text + "\"]\n";
    }
}

class GroupToken extends Token {

    ArrayList<Token> tokens = new ArrayList<>();

    public GroupToken() { }

    public void add(Token token) {
        this.tokens.add(token);
    }

    @Override
    public String toString() {
        return toString(0);
    }

    @Override
    public String toString(int indent) {
        String out = "GroupToken[\n";
        for (Token t : this.tokens) {
            out += StringUtils.pad("", 4 * (indent + 1), ' ') + t.toString(indent + 1);
        }
        out += StringUtils.pad("", 4 * indent, ' ') + "]\n";
        return out;
    }

}
公共类主{
私有静态void构建树(字符串格式){
Stack st=新堆栈();
StringBuilder sb=新的StringBuilder();
GroupToken根=新的GroupToken();
圣推(根);
布尔值var=false;
对于(int i=0;i