Come posso taggare il testo in base alla sua indentazione?


-1

Voglio taggare il contenuto testuale (con tag tipo XML) in base alla sua profondità di indentazione. Le righe vuote dovrebbero essere preservate. L'esempio seguente ha il suo contenuto rientrato con 1, 2 o 3 schede.

INGRESSO

aaa
  bbb
  bbb

aaa

      ccc
      ccc
  bbb
  bbb

Voglio raggruppare le linee allo stesso livello di indentazione e traduci i livelli di indentazione nei tag x, y e z, come questo:

PRODUZIONE

<x>aaa</x>
     <y>bbb
        bbb</y>

 <x>aaa</x>

        <z>ccc
           ccc</z>
    <y>bbb
       bbb</y>

Come posso fare questo?


Se vuoi aggiungere delle righe vuote (come hai mostrato), dovresti dirlo. E il tuo esempio è incoerente: confronta i due <b> strofe.
Scott

Ho modificato la domanda in base alla tua opinione.
Ramaprakasha

Grazie per aver corretto il rientro incoerente dei tag rispetto ai dati, ma non hai rispettato le linee vuote. Il set di dati di input ha dieci righe: line1 è "111", lines2 e3 sono entrambi "222", line4 è vuoto, ecc. L'output è lungo dodici righe, non solo preservando le righe vuote preesistenti, ma aggiungendo uno a 1½ (tra "222" e "111") e un altro a 8½ (tra "333" e "222"). Vuoi che ciò accada? (O è un errore di battitura nella tua domanda?)
Scott

Oh scusa. Sì, era un errore di battitura. L'ho corretto ora.
Ramaprakasha

Dal momento che volevo tagging del testo ho cambiato i numeri in a, b, c.
Ramaprakasha

Risposte:


0

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.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.