Wie kann ich Text anhand seiner Einrückung kennzeichnen?

-1

Ich möchte Textinhalte (mit XML-ähnlichen Tags) anhand ihrer Einrückungstiefe kennzeichnen. Leerzeilen sollten beibehalten werden. Der Inhalt des folgenden Beispiels wird mit 1, 2 oder 3 Registerkarten eingerückt.

EINGANG

aaa
  bbb
  bbb

aaa

      ccc
      ccc
  bbb
  bbb

Ich möchte mit der gleichen Einzugsebene zu Gruppenleitungen und diese Einrückungen um Schlagworte übersetzen x, yund z, wie folgt aus :

AUSGABE

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

 <x>aaa</x>

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

Wie kann ich das machen?

Ramaprakasha
quelle
Wenn Sie möchten, dass Leerzeilen hinzugefügt werden (wie Sie gezeigt haben), sollten Sie dies sagen. Und Ihr Beispiel ist inkonsistent - vergleichen Sie die beiden <b>Strophen.
Scott
Ich habe die Frage aufgrund Ihrer Meinung bearbeitet.
Ramaprakasha
Vielen Dank, dass Sie die inkonsistente Einrückung der Tags im Vergleich zu den Daten behoben haben, aber Sie haben meinen Standpunkt zu Leerzeilen verfehlt. Ihr Eingabedatensatz enthält zehn Zeilen: Zeile 1 ist "111", Zeile 2 und 3 sind beide "222", Zeile 4 ist leer usw. Ihre Ausgabe ist zwölf Zeilen lang, wobei nicht nur die bereits vorhandenen Leerzeilen beibehalten, sondern auch hinzugefügt werden eine bei 1½ (zwischen „222“ und „111“) und eine bei 8½ (zwischen „333“ und „222“). Möchten Sie, dass das passiert? (Oder ist es ein Tippfehler in Ihrer Frage?)
Scott
Oh, Entschuldigung. Ja, es war ein Tippfehler. Ich habe es jetzt korrigiert.
Ramaprakasha
Da ich Tagging von Text wollte ich änderte Zeichen a, b, c.
Ramaprakasha

Antworten:

0

Problemstellung:

Eine Eingabedatei enthält Text, der mit null oder mehr Tabulatorzeichen eingerückt ist. Im Einzelnen ist jede Zeile in der Eingabe eine der folgenden:

  • Leer oder
  • Null oder mehr Tabulatoren (bis zu einer Grenze; ​​siehe unten), gefolgt von einem Zeichen, das weder ein Leerzeichen noch ein Tabulator ist (gefolgt von null oder mehr Zeichen).

Es gibt keine Zeilen, die

  • Beginnen Sie mit null oder mehr Tabulatoren, gefolgt von einem Leerzeichen. (Dies impliziert, dass es keine Zeilen gibt, die mit einem Leerzeichen beginnen.)
    Oder
  • Besteht ausschließlich aus einer oder mehreren Registerkarten (und nichts anderem).
    oder
  • Beginnen Sie mit mehr als einer festgelegten Anzahl von Registerkarten.

Die Eingabe wird logisch in Gruppen von Zeilen zerlegt, die alle entweder sind

  • Leer oder
  • Mit der gleichen Anzahl von Tabulatoren eingerückt.

Leerzeilen werden unverändert an den Ausgang durchgereicht.

Es ist eine Liste von Tags anzugeben. zB x, yund zz. Eine Gruppe von (nicht leeren) Zeilen, die mit Null-Tabulatoren eingerückt sind (dh nicht eingerückt sind), muss zwischen <x>und stehen </x>. Eine Gruppe von Zeilen, die mit einem Tabulator eingerückt sind, muss in <y>und stehen </y>. Eine Gruppe von Zeilen, die mit zwei Tabulatoren eingerückt sind, muss zwischen <zz>und stehen </zz>. (Zeilen werden nicht mit mehr als zwei Tabulatoren eingerückt.)

In der ersten Zeile einer Gruppe (von nicht leeren Zeilen) muss das Anfangsetikett zwischen den Tabulatoren und dem Text eingefügt werden. In der letzten Zeile einer Gruppe muss das End-Tag am Ende des Textes angehängt werden. Eine Gruppe kann aus einer einzelnen Zeile bestehen, sodass die erste Zeile auch die letzte Zeile sein kann. Alle Zeilen einer anderen Gruppe als der ersten werden zusätzlich um die Breite des Anfangstags eingerückt (mit Leerzeichen zwischen den Tabulatoren und dem Text).

Zum Beispiel (mit  ―→ , um eine Registerkarte darzustellen), diese EINGABE :

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.

soll in dieses OUTPUT übersetzt werden :

<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>

Lösung:

Offensichtlich wissen wir nicht genau, was wir mit einer Eingabezeile tun sollen, bis wir die nächste Zeile gelesen haben. Dieses Problem wird normalerweise behoben, indem der Inhalt einer zu verarbeitenden Zeile gespeichert wird, nachdem die nächste gelesen wurde.

Hier ist es also:

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] ">"
    }
    '

Der BEGIN-Block initialisiert die Tags ( x, yund zz) durch Aufteilen einer durch Leerzeichen getrennten Zeichenfolge. Das tag_padArray enthält genügend Leerzeichen, um mit der Breite der Tags übereinzustimmen (einschließlich <und >): tag_pad[1]und tag_pad[2]drei Leerzeichen; tag_pad[3]ist vier Leerzeichen.

Wenn wir eine Eingabezeile lesen, analysieren wir sie. Wenn es keine Felder ( NF == 0) enthält, muss es leer sein (da wir angegeben haben, dass keine Zeile ausschließlich aus Leerzeichen und Tabulatoren besteht). Setzen Sie es indent_numauf 0. Anderenfalls messen Sie den Einzug, indem Sie die Position von $1(dem ersten Wort) in $0(ermitteln. die gesamte Zeile).  indexGibt einen Wert ab 1 zurück. Dies ist also eine Stelle mehr als die Anzahl der Leerzeichen vor dem ersten Nicht-Leerzeichen (und wir gehen davon aus, dass dies alle Registerkarten sind). Das ist ein Glücksfall, denn jetzt indent_num entspricht es den Einträgen in den Arrays tagsund tag_pad. Dann teilen wir die Zeile in ein indent_str(Leerzeichen) und ein restOfLine(alles nach dem Einzug).

Jetzt verlassen wir uns auf gespeicherte Informationen. Wenn diese Zeile einen anderen Einzug hat als die vorherige, beginnen wir eine neue Gruppe. Wenn es ist eine gespeicherte Zeile, schreiben Sie es aus, mit dem entsprechenden End - Tag am Ende der Zeile.

Wenn die aktuelle Zeile leer ist, drucken Sie sie einfach aus. Überprüfen Sie, ob die aktuelle Einrückungsstufe zu hoch ist, und sichern Sie sie, falls dies der Fall ist. Wenn der aktuelle Einzug mit dem vorherigen identisch ist, handelt es sich um eine Fortsetzung einer bereits gestarteten Gruppe. Drucken Sie daher einfach die gespeicherte (vorherige) Zeile und erstellen Sie eine neue savedZeichenfolge, die der aktuellen Zeile mit der Breite des aktuellen Einzugs entspricht Tag, das zwischen dem Einzug und dem Text eingefügt wird. Andernfalls starten wir eine neue Gruppe. Erstellen Sie daher eine savedZeichenfolge, die die aktuelle Zeile mit dem Starttag (selbst) zwischen dem Einzug und dem Text darstellt.

Wenn wir am Ende der Eingabe angelangt sind, beenden Sie die aktuelle Gruppe wie zuvor.

Scott
quelle