Algoritmo - Numeración de TOC (Tabla de Contenidos)

votos
3

Quiero implementar una función de VBA para Excel filas de números basados ​​en la profundidad agrupación de la fila.

Pero creo que un algoritmo general para la generación de TOC es más interesante.

El problema es:

Dada una lista de líneas sangría, tales como

One
 Two
  Three
   Four
 Five
Six

(El nivel de sangría puede suponerse a ser conocido y parte de los datos de entrada)

Para generar la salida siguiente:

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

Por supuesto mi código está en marcha ... y también oculta bajo THWoS (el peso pesado de la vergüenza)

Publicado el 01/06/2010 a las 00:20
fuente por usuario
En otros idiomas...                            


2 respuestas

votos
8

Utilice una pila de los números. Loop a través de cada fila, y comprobar el nivel de sangrado de cada fila, sin indentación ser nivel 1.

  1. Si el nivel de sangría actual es mayor que el tamaño del empuje pila como muchos otros como la diferencia está en la pila (la diferencia por lo general sería sólo uno, pero esto funciona incluso si alguien pone un encabezado de nivel 3 en una partida de nivel 1, por ejemplo)
  2. Si el nivel de sangría actual es menor que el tamaño de la pila, el pop y descartar tantos números como la diferencia es y luego incrementar el número de arriba en la pila.
  3. Si el nivel de sangría actual es igual al tamaño de la pila, incrementar el número de arriba en la pila

Para cada fila, el número del título actual es los números de la pila concatenados con una. para separarlos.

Nótese cómo el tamaño de la pila representa holgadamente nivel de sangría de la línea anterior.

Para las personas que les resulta más fácil de leer el código, he aquí una implementación de JavaScript para navegadores modernos:

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;
});

Respondida el 01/06/2010 a las 00:33
fuente por usuario

votos
2

Este algoritmo supone que el nivel de sangría nunca se incrementa en más de 1 unidad. Si lo hace, entonces debe configurar todos los niveles "saltado" a 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
Respondida el 01/06/2010 a las 00:42
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more