6 Stimmen

Bash oder Python, um zurückzugehen?

Ich habe eine Textdatei, in der sehr häufig die Zeichenfolge @STRING_A vorkommt, und ich wäre daran interessiert, ein kurzes Skript zu schreiben, das nur einige davon entfernt. Insbesondere eines, das die Datei durchsucht und sobald es eine Zeile findet, die mit dieser Zeichenfolge beginnt, wie

@STRING_A

dann überprüft, ob es 3 Zeilen rückwärts ein weiteres Vorkommen einer Zeile gibt, die mit derselben Zeichenfolge beginnt, wie

@STRING_A

@STRING_A

und wenn dies geschieht, das Vorkommen 3 Zeilen rückwärts löscht. Ich dachte an bash, aber ich weiß nicht, wie ich damit "rückwärts gehen" soll. Ich bin also sicher, dass dies mit bash nicht möglich ist. Ich dachte auch an python, aber dann müsste ich alle Informationen im Speicher speichern, um rückwärts zu gehen und dann wäre es bei langen Dateien unpraktikabel.

Was denkst du? Ist es möglich, dies in bash oder python zu tun?

Danke

-2voto

SashaN Punkte 679

Ich würde erwägen, sed zu verwenden. Gnu sed unterstützt die Definition von Zeilenbereichen. Wenn sed versagen würde, dann gibt es ein weiteres Biest - awk und ich bin sicher, du kannst es mit awk machen.

O.K. Ich fühle, dass ich mein awk POC einfügen sollte. Ich konnte nicht herausfinden, wie man sed-Adressen verwendet. Ich habe noch nicht die Kombination von awk+sed ausprobiert, aber es scheint mir, dass es übertrieben ist.

Mein awk-Skript funktioniert wie folgt:

  • Es liest Zeilen und speichert sie in einem 3-Zeilen-Puffer

  • Wenn das gewünschte Muster gefunden wird (/^data.*/ in meinem Fall), wird der 3-Zeilen-Puffer überprüft, ob das gewünschte Muster drei Zeilen zuvor gesehen wurde

  • Wenn das Muster gesehen wurde, werden 3 Zeilen gelöscht

um ehrlich zu sein, würde ich wahrscheinlich auch mit Python gehen, da awk wirklich umständlich ist. Der AWK-Code lautet:

function max(a, b)
{
    if (a > b)
        return a;
    else
        return b;
}

BEGIN {
    w = 0;  #Schreibindex
    r = 0;  #Leseindex
    buf\[0, 1, 2\];   #Puffer
}

END {
    # Puffer leeren
    # starte beim Leseindex und gib bis zum Index w aus
    for (k = r % 3; k  r - max(r - 3, 0); k--) {
        #suche im 3-Zeilen-Verlauf buf
        if (match(buf\[k % 3\], /^data.\*/) != 0) {
            # gefunden -> Zeilen aus dem Verlauf entfernen
            # indem sie überschrieben werden -> Schreibindex anpassen
            w -= max(r, 3);
        }
    }
    buf\[w % 3\] = $0;
    w++;
}

/^.\*/ {
    # speichere Zeile in Puffer, wenn der Verlauf
    # voll ist, gib die älteste aus.
    if (w > 2) {
        print buf\[r % 3\];
        r++;
        buf\[w % 3\] = $0;
    }
    else {
        buf\[w\] = $0;
    }
    w++;
}

0 Stimmen

Awk könnte es wahrscheinlich alleine tun... aber ich vermute, es ist sauberer, tatsächlich awk+sed zu verwenden, wie in meiner obigen Lösung.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X