C'è una regola scritta: quando rompi una sezione in sottosezioni, in genere dovrebbe avere più di una sottosezione. Questo risale alle vecchie regole di composizione del liceo: se hai una sezione A. hai anche bisogno di una sezione B.
Per controllare un capitolo di un libro che sto scrivendo in LaTeX, faccio questo:
$ egrep -h '^\(chapter|(sub)*section)\**{' CHAPTERFILE.tex | sed -e 's/\*{/{/g'
\chapter{My Chapter}
\section{Topic}
\subsection{Subtopic}
\subsection{Another Subtopic}
\subsection{Subtopic the Third}
\section{More}
\subsection{More more}
\subsection{Less is more}
\section{Odyssey}
\subsection{Marge and Homer}
\subsubsection{Bart}
\subsubsection{Lisa}
\subsubsection{Maggie}
\subsection{Example}
\section{Lore}
\section{Data}
Che cos'è un algoritmo efficace per verificare che la regola sia stata rispettata? Questa regola vale per le sottosezioni in una sezione, le sottosezioni in una sottosezione e così via. (Anche se nel mio caso non ci sono sezioni subsubsub)
Grazie al consiglio di Bart, ecco il codice che ho creato. È hacky in alcuni punti, ma è semplice e trova bug nei file LaTeX:
#!/usr/bin/env python
import sys
import fileinput
TOKENS = [
['\chapter', 0],
['\section', 1],
['\subsection', 2],
['\subsubsection', 3],
['\subsubsubsection', 4],
]
def getlevel(line):
"""Report the line's level (number of subsections)."""
for token, level in TOKENS:
if line.startswith(token):
return level
raise Exception()
def store(lst, level, value):
"""Store value in the level'th position."""
while len(lst) < level:
lst.append('EMPTY')
return lst[:level] + [value]
def segments():
"""Read the input text, yield lists of segments."""
path = []
last_level = 0
for line in fileinput.input():
value = line[line.index('{') + 1 : line.index('}')]
path = store(path, getlevel(line), value)
yield path
def get_tree(segs):
"""Build a tree out of segment lists returned by generator segs"""
tree = {}
for s in segs():
t = tree
for i in s:
t = t.setdefault(i, {})
return tree
def audit(t):
"""Audit: Leafs are ok, nodes are ok if they have >1 children."""
error = False
for k, v in t.items():
if audit(v):
error = True
if len(v) == 1:
print 'ERROR: part with only one subpart: %s' % (k, )
error = True
return error
def main():
tree = get_tree(segments)
if audit(tree):
return 1
if __name__ == '__main__':
sys.exit(main())