7

我要做一些简单的 RTF 文本解析,我需要纠正一个问题。给定以下字符串:

{aaaaaaa\}aaaa\{aaaaa{bbbbbbbb{ccccc\{cccc}bbb{eeeee}{{gggg}ffff}bbbbbb}aaaaa}

在哪里:

\ means ignore next character
{ means expand
} means collapse up to parent

在字符串中的任何点,状态都可能受到任何先前字符的影响,除了封闭标签中的字符。例如 {gggg} 不会影响 ffff 但 aaaaaaa}aaa.. 会影响bbbb, ccc, eee, ggg, fff等等。

由此我们可以将上述内容拆分为有意义的块

A1 = aaaaaaa\}aaaa\{aaaaa
B1 = bbbbbbbb
C = ccccc\{cccc
B2 = bbb
E = eeeee
G = gggg
F = ffff
B3 = bbbbbb
A2 = aaaaa

产量:

{A1{B1{C}B2{E}{{G}F}B3}A2}

为了描述我使用 X > Y 的依赖关系,意味着 Y 依赖于 X(因为 X 可能会改变 Y 的含义)

A1
A1 > B1
A1 > B1 > C
A1 > B1 > B2
A1 > B1 > B2 > E
A1 > B1 > B2 > G
A1 > B1 > B2 > F
A1 > B1 > B2 > B3
A1 > B1 > B2 > A2
A1 > A2

因此,如果我们有一个可以具有值和子值的有序列表的节点。这样价值树看起来像这样:

A1
- B1
- - C
- - B2
- - - E
- - - G
- - - F
- - - B3
- A2

然后要获得影响任何节点的字符,我可以递归地逐步遍历每个父节点。

我一直卡在试图将字符串解析到我的节点类中:

public class myNode
{
    public myNode Parent;
    public string Value;
    public List<myNode> subNodes;
}

我逐个字符地读取字符串,当我遇到 a 时,\我增加了 2。当我遇到 a 时,{我将之前的文本部分保存为节点值并进入子节点,当我遇到 a 时,我会}退出。

但我一直在搞乱逻辑,尤其是对于Gand A2。在纸上做起来很简单,但是当我尝试做实际的下台逻辑时,我一直把它搞砸了。

有没有更直接的方法来制作这种结构?(或者我应该使用更好的结构)。我认为应该有一些库允许将字符串转换为树,但我似乎找不到任何东西。

4

1 回答 1

5

使用“状态机”方法,其中状态是当前节点和转义标志:

string rtf = @"{aaaaaaa\}aaaa\{aaaaa{bbbbbbbb{ccccc\{cccc}bbb{eeeee}{{gggg}ffff}bbbbbb}aaaaa}";

Node root = new Node { Parent = null, Value = "root", SubNodes = new List<Node>() };
Node node = root;
bool escape = false;
foreach (char c in rtf) {
  if (escape) {
    node.Value += c;
    escape = false;
  } else {
    switch (c) {
      case '{':
        node = new Node { Parent = node, Value = String.Empty, SubNodes = new List<Node>() };
        node.Parent.SubNodes.Add(node);
        break;
      case '}':
        node = new Node { Parent = node.Parent.Parent, Value = String.Empty, SubNodes = new List<Node>() };
        if (node.Parent != null) node.Parent.SubNodes.Add(node);
        break;
      case '\\':
        escape = true;
        break;
      default:
        node.Value += c;
        break;
    }
  }
}

PrintNode(root, String.Empty);

Node 类(只是重命名了一点):

public class Node {
  public Node Parent;
  public string Value;
  public List<Node> SubNodes;
}

对于显示:

private static void PrintNode(Node node, string level) {
  if (node.Value.Length > 0) Console.WriteLine(level + node.Value);
  foreach (Node n in node.SubNodes) {
    PrintNode(n, level + "  ");
  }
}

输出:

root
  aaaaaaa}aaaa{aaaaa
    bbbbbbbb
      ccccc{cccc
    bbb
      eeeee
        gggg
      ffff
    bbbbbb
  aaaaa

请注意,G 节点不是 E 节点的子节点,而是具有空值的节点的子节点。

当然,您还必须添加一些错误处理。

于 2012-05-04T09:42:28.740 回答