Resoconto del problema:
Un file di input ha un testo, rientrato da zero o più caratteri di tabulazione.
Nello specifico, ogni riga nell'input è una di queste:
- Vuoto, o
- Zero o più schede (fino a un limite, vedi sotto),
seguito da un personaggio che non è né uno spazio né una tabulazione
(seguito da zero o più di qualsiasi carattere).
Ci sono no linee che
- Inizia con zero o più schede, seguito da uno spazio.
(Ciò implica che non ci sono linee che iniziano con uno spazio).
o
- Consiste interamente di una o più schede (e nient'altro).
o
- Inizia con più di un numero specificato di schede.
L'input deve essere logicamente scomposto in gruppi di linee
questo sono tutti o entrambi
- Vuoto, o
- Indented con lo stesso numero di schede.
Le righe vuote devono essere passate all'output, non modificate.
Deve essere specificato un elenco di tag; per esempio., x
, y
, e zz
.
Un gruppo di linee (non vuote) con rientro a schede zero
(cioè, non dentellato) deve essere tra parentesi <x>
e </x>
.
Un gruppo di linee rientrate in una scheda
deve essere tra parentesi <y>
e </y>
.
Un gruppo di linee che sono rientrate con due schede
deve essere tra parentesi <zz>
e </zz>
.
(Le linee non saranno rientrate con più di due schede.)
La prima riga di un gruppo (di linee non vuote)
deve avere il tag iniziale inserito tra le schede e il testo.
L'ultima riga di un gruppo deve avere il tag di chiusura
aggiunto alla fine del testo.
Un gruppo può consistere in una singola riga,
quindi la prima riga potrebbe anche essere l'ultima riga.
Tutte le linee di un gruppo diverso dal primo devono essere ulteriormente indentate
(con spazi inseriti tra le schede e il testo)
dalla larghezza del tag iniziale.
Ad esempio (utilizzando ―→
rappresentare una scheda), questo INGRESSO :
aaa
―→ Once upon a midnight dreary,
―→ while I pondered, weak and weary,
Quoth the Raven, “Nevermore.”
―→ ―→ The quick brown fox
―→ ―→ jumps over the lazy dog.
―→ It was a dark and stormy night.
―→ Suddenly a shot rang out.
deve essere tradotto in questo PRODUZIONE :
<x>aaa</x>
―→ <y>Once upon a midnight dreary,
―→ while I pondered, weak and weary,</y>
<x>Quoth the Raven, “Nevermore.”</x>
―→ ―→ <zz>The quick brown fox
―→ ―→ jumps over the lazy dog.</zz>
―→ <y>It was a dark and stormy night.
―→ Suddenly a shot rang out.</y>
Soluzione:
Ovviamente, non sappiamo bene cosa fare con una linea di input
finché non avremo letto la riga successiva.
Solitamente questo problema viene risolto salvando il contenuto di una riga
da elaborare dopo aver letto quello successivo.
Quindi, eccolo qui:
awk '
BEGIN {
num_tags = split("x y zz", tags)
for (i=1; i<=num_tags; i++)
{
len = length(tags[i]) + 2
tag_pad[i] = ""
for (j=1; j<=len; j++) tag_pad[i] = tag_pad[i] " "
}
}
{
if (NF == 0)
indent_num = 0
else
{
indent_num = index($0, $1)
indent_str = substr($0, 1, indent_num-1)
restOfLine = substr($0, indent_num)
}
if (indent_num != saved_indent_num && saved != "")
{
print saved "</" tags[saved_indent_num] ">"
saved = ""
}
if (NF == 0)
print
else if (indent_num > num_tags)
{
errmsg = "Error: line %d has an indent level of %d.\n"
printf errmsg, NR, indent_num > "/dev/stderr"
exit 1
}
else if (indent_num == saved_indent_num)
{
print saved
saved = indent_str tag_pad[indent_num] restOfLine
}
else
saved = indent_str "<" tags[indent_num] ">" restOfLine
saved_indent_num = indent_num
}
END {
if (saved != "")
print saved "</" tags[saved_indent_num] ">"
}
'
Il blocco BEGIN inizializza i tag ( x
, y
, e zz
)
dividendo una stringa separata dallo spazio.
Il tag_pad
la matrice contiene abbastanza spazi
per abbinare la larghezza dei tag (incluso il <
e >
): tag_pad[1]
e tag_pad[2]
sono tre spazi; tag_pad[3]
sono quattro spazi.
Leggendo una riga di input, la analizziamo.
Se non ha campi ( NF == 0
), deve essere vuoto
(poiché abbiamo specificato che nessuna riga è composta interamente da spazi e tabulazioni),
così impostato indent_num
a 0.
Altrimenti, misura il rientro
trovando la posizione di $1
(la prima parola) in $0
(l'intera linea). index
restituisce un valore a partire da 1,
quindi questo è in realtà un numero in più rispetto al numero di caratteri bianchi
prima del primo carattere non di spazi bianchi
(e, ricorda, stiamo assumendo che queste siano tutte schede).
Questo è fortunato, perché ora indent_num
corrisponde alle voci nel tags
e tag_pad
array.
Quindi dividiamo la linea in un indent_str
(lo spazio bianco)
e restOfLine
(tutto dopo il trattino).
Ora ci basiamo su informazioni salvate.
Se questa linea ha un rientro diverso da quello precedente,
stiamo iniziando un nuovo gruppo.
Se ci è una linea salvata,
scrivilo, con il tag di fine appropriato alla fine della riga.
Se la riga corrente è vuota, basta stamparla.
Controlla se il livello di indentazione corrente è troppo alto, e cauzione se lo è.
Se il rientro corrente è uguale al precedente,
questa è una linea di continuazione di un gruppo già avviato,
quindi basta stampare la riga salvata (precedente),
e costruisci un nuovo saved
stringa che è la riga corrente
con la larghezza di il tag corrente inserito tra il rientro e il testo.
Altrimenti, stiamo iniziando un nuovo gruppo,
quindi costruisci un saved
stringa che è la riga corrente
con il tag iniziale (stesso) inserito tra il rientro e il testo.
Quando arriviamo alla fine dell'input, termina il gruppo corrente come facevamo prima.
<b>
strofe.