我正在努力将带括号的字符串(例如f(d(a c(b))e)
)转换为Java中的Tree数据结构(我正在研究一种允许使用字符串表示来实例化Tree的方法)。在上面的字符串中,f
是树的根节点,它分支到d
的子树和e
的叶节点。在我能够将f
标识为当前节点的标签后,我留下了d(a c(b))e
。
我希望能够使用Java的正则表达式来识别孩子;在这种情况下,d(a c(b))
和e
。因此,要求如下。
在字符串中,单个字符可能会或可能不会被括号括起来。如果后跟括号,则返回内部的所有子字符串,即使它包含嵌套的括号。因此,正则表达式将匹配d(a c(b))
或e
。
此外,我希望这不仅仅适用于有两个孩子的节点。可能带括号的字符串可能是f(a b c)
,这是一个以f
为根,有3个叶子的树。
到目前为止,我有.\(?[^\(\)]\)?
,但这不起作用。
答案 0 :(得分:4)
使用正则表达式是不可能的,请参阅Can regular expressions be used to match nested patterns?
使用StreamTokenizer和递归代替,应该看起来与此类似(未经测试):
public class Node {
private String name;
private ArrayList<Node> children = new ArrayList<Node>();
public static Node parseTree(String s) throws IOException {
StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(s));
tokenizer.nextToken(); // Move to first token
Node result = new Node(tokenizer); // Parse root node (and children)
if (tokenizer.ttype != StreamTokenizer.TT_EOF) {
throw new RuntimeException("Leftover token: "+ tokenizer.ttype);
}
return result;
}
Node(StreamTokenizer tokenizer) throws IOException {
if (tokenizer.ttype != StreamTokenizer.TT_WORD) {
throw new RuntimeException("identifier expected; got: " + tokenizer.ttype);
}
name = tokenizer.sval; // read then name
if (tokenizer.nextToken() == '(') { // Consume the name and check for Children
tokenizer.nextToken(); // Yes, consume '('
do {
children.add(new Node(tokenizer)); // Add and parse a child
} while (tokenizer.ttype != ')'); // Until we reach ')'
tokenizer.nextToken(); // Consume ')'
}
}
}
(如果节点名称都是单个字符且分隔符始终只是一个空格,则可以在没有StreamTokenizer的情况下编写稍微简单的递归解析代码)