3

行のグループ化の深さに基づいてExcelの行に番号を付けるVBA関数を実装したいと思います。

しかし、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(The Heavy Weight of Shame)の下にも隠されています

4

2 に答える 2

8

数字にはスタックを使用します。各行をループし、各行のインデントレベルを確認します。インデントはレベル1ではありません。

  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 に答える