我正在构建由非常自定义语言驱动的自定义资源提供程序。为此,我必须从自定义表达式创建树数据结构。让我解释一下:
f1(f2,f3,f6(f4),f5)
上面是我的自定义表达式的示例,我想从中构建树。 Root - f1
,有子女:f2
,f3
,f4
,f5
。但f4
也有自己的孩子。
我已经为这个问题编写了解决方案,但我想找到更好的方法来实现这个目标。
class Node
{
public string val;
public List<Node> child = new List<Node>();
}
private Node parseInput(string input, int index)
{
string nodeName = findToken(input,ref index);
Node tmp = new Node() { val = nodeName };
tmp.child = expandNodes(input, ref index);
return tmp;
}
private List<Node> expandNodes(string input, ref int index)
{
List<Node> res = new List<Node>();
while (!char.IsLetterOrDigit(input[index++]) && index < input.Length) ;
index--;
while (index < input.Length)
{
if (checkNext(input, index, ')'))
{
while (!char.IsLetterOrDigit(input[index++]) && index < input.Length) ;
index--;
return res;
}
Node tmp = new Node() { val = findToken(input,ref index) };
if (checkNext(input, index, '('))
{
tmp.child = expandNodes(input, ref index);
}
res.Add(tmp);
}
return res;
}
private bool checkNext(string s, int index, char desiredChar)
{
string vc = "" + s[index];
while (index < s.Length && !char.IsLetterOrDigit(s[index]))
{
char chr = s[index];
if (chr == desiredChar)
{
return true;
}
index++;
}
return false;
}
private string findToken(string s, ref int index)
{
string res = null;
while (!char.IsLetterOrDigit(s[index++]) && index < s.Length) ;
index--;
while (index < s.Length && char.IsLetterOrDigit(s[index]))
{
res += s[index];
index++;
}
return res;
}
答案 0 :(得分:2)
我宁愿将Parse
作为 静态方法 添加到Node
类中:
// Simplified implementation: some checks removed, many useful methods omitted
public class Node {
private String m_Title;
private Node m_Parent;
private List<Node> m_Items = new List<Node>();
public Node(String title) {
m_Title = title;
}
public Node Parent {
get {
return m_Parent;
}
}
public IReadOnlyList<Node> Items {
get {
return m_Items;
}
}
public void Add(Node value) {
m_Items.Add(value);
value.m_Parent = this;
}
public String Title {
get {
return m_Title;
}
}
public override String ToString() {
if (m_Items.Count <= 0)
return m_Title;
StringBuilder Sb = new StringBuilder();
Sb.Append(m_Title);
Sb.Append("(");
for (int i = 0; i < m_Items.Count; ++i) {
Sb.Append(m_Items[i].ToString());
if (i < m_Items.Count - 1)
Sb.Append(",");
}
Sb.Append(")");
return Sb.ToString();
}
public static Node Parse(String value) {
Node owner = null;
Node current = null;
StringBuilder Sb = new StringBuilder();
foreach (Char ch in value) {
if (Char.IsLetterOrDigit(ch))
Sb.Append(ch);
else {
if (Sb.Length > 0) {
current = new Node(Sb.ToString());
Sb.Length = 0;
if (owner != null)
owner.Add(current);
else
owner = current;
}
if (ch == '(')
owner = current;
else if (ch == ')' && (owner.Parent != null))
owner = owner.Parent;
}
}
// Tail
if (Sb.Length > 0) {
current = new Node(Sb.ToString());
Sb.Length = 0;
if (owner != null)
owner.Add(current);
else
owner = current;
}
return owner;
}
}
...
Node test = Node.Parse("f1(f2,f3,f6(f4),f5)");
String check = test.ToString(); // <- "f1(f2,f3,f6(f4),f5)"
答案 1 :(得分:0)
我会使用正则表达式匹配和递归调用,例如:
class Node {
public string val;
public List<Node> children = new List<Node>();
public static Node Parse(string input) {
Node n = new Node();
//extract value and children
Regex reg = new Regex("(?<val>\\w+)(?:\\((?<children>(?:\\([^()]*\\)|.)*)\\))?");
// fill value
Match match = reg.Match(input);
n.val = match.Groups["val"].Value;
// if children group matched
if (match.Groups["children"].Success) {
// split through commas outside of parenthesis
string[] childrenTab = Regex.Split(match.Groups["children"].Value, ",(?![^(]*\\))");
// and call recursively for each child
foreach (string child in childrenTab) {
n.children.Add(Node.Parse(child));
}
}
return n;
}
此外,静态方法似乎更合适。