2013-04-05 29 views
3

我试图做一个字符串格式化机制,这几乎看起来像Winamp Advanced Title Formatting如何在Java中创建字符串格式化机制?

我有一些'变量'(或元数据字段)绑定到对象属性,形式为%varname%。因此,例如,元数据字段绑定到歌曲标题,例如'征服天堂',元数据字段被绑定到歌曲艺术家,例如'Vangelis'和%feat%元数据字段必须与特色的艺术家一致,比如'English Chamber Choir'。

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

%title%[ (by %artist%[ featuring %feat%])] 

方括号表示不显示,除非(全部)括号内的元数据进行设置。应该可以嵌套方括号。
所以上述格式化字符串说:显示的元数据字段%标题%,如果%的艺术家%设置(不是空字符串),显示(by %artist%),但如果%壮举%元数据字段也非 - 空,然后显示该字段也。在上述例子中,它会成为:

征服天堂(范吉利斯特色英语室内合唱团)

现在我该怎样做出这样的机制?我从哪说起呢?

我想我必须标记字符串,然后按'部分'搜索元数据标记?

+0

那么你真正想要的是标记,而不是格式?对于格式化,请阅读Javadoc以获取String.format()。 – Axel 2013-04-05 06:59:01

回答

3

我会建立一个代表模式的树形结构。对于你的榜样,它看起来像:

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

所有剩下要做的就是找出如何解析你的字符串创建树结构。

1

根据SimonCsuggestion,我写了一个tokenizer来执行已经建议的东西,将格式化字符串拆分为令牌。

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

} 
相关问题