3

我想实现一个 VBA 函数来根据行的分组深度对 Excel 行进行编号。

但我认为生成 TOC 的通用算法更有趣。

问题是:

给定一个“缩进”行的列表,例如

One
 Two
  Three
   Four
 Five
Six

(可以假设“缩进级别”是已知的并且是输入数据的一部分)

要生成以下输出:

1.    One
1.1    Two
1.1.1   Three
1.1.1.1  Four
1.2    Five
2.    Six

当然,我的代码已经启动并正在运行......并且还隐藏在 THWoS(耻辱的重量)下

4

2 回答 2

8

使用堆栈作为数字。循环遍历每一行,并检查每一行的缩进级别,没有缩进级别为 1。

  1. 如果当前缩进级别大于堆栈的大小,则将差异推入堆栈的数量(差异通常只有一个,但即使有人将级别 3 标题放在级别 1 标题下,这也有效,例如)
  2. 如果当前缩进级别小于堆栈的大小,则弹出并丢弃与差异相同的数字,然后递增堆栈上的顶部数字。
  3. 如果当前缩进级别等于栈的大小,则递增栈顶数

对于每一行,当前的标题编号是堆栈上的数字与 . 将它们分开。

请注意堆栈的大小如何方便地表示上一行的缩进级别。

对于那些发现代码更容易阅读的人来说,这里有一个适用于现代浏览器的 JavaScript 实现:

const toc = `
One
 Two
  Three
   Four
 Five
  Six
  Seven
 Eight
Nine
Ten
`;

let stack = [];

toc.trim().split(/\n/g).forEach(line => {
  // Gets the identitation level with 1 being no indentation and so forth
  let level = line.match(/^\s*/)[0].length + 1;

  if (level > stack.length) {
    while (level > stack.length)
      stack.push(1);
  } else {
    while (level < stack.length)
      stack.pop();

    stack[stack.length - 1]++;
  }
  
  let title = stack.join(".") + ". " + line.trim();

  document.body.appendChild(document.createElement("div")).innerText = title;
});

于 2010-05-31T23:33:30.890 回答
2

该算法假设缩进级别不会增加超过 1 个单位。如果是这样,那么您必须将所有“跳过”级别设置为 1。

#use a vector instead, if your language supports it
numbering = {0, 0, 0, 0, 0, 0, 0}

for line in lines:
    level = indentLevel(line) #starting from 0

    numbering[level] = numbering[level] + 1
    numbering[level + 1] = 0 #create it if it doesn't exist
    for n = 0 to level - 1
        print numbering[n], ".",
    print numbering[level], " ", line
于 2010-05-31T23:42:49.460 回答