AWK: Zeilen mit 72 Zeichen umbrechen


7
$ awk 'length > 72' {HOW TO PRINT THE LINEs IN PCS?} msg

Das heißt, ich möchte, dass es \nnach 72 Zeichen hinzugefügt wird und fortfährt. Daher müssen Sie zunächst möglicherweise alle einzelnen Zeichen entfernen \nund sie hinzufügen. Es mag einfacher sein, mit anderen Werkzeugen einfacher zu sein, aber versuchen wir es mit awk.

[Aktualisieren]

Williamson gab die richtige Antwort, aber es brauchte etwas Hilfe, um sie zu lesen. Ich teile das Problem mit einfacheren Beispielen in Teile auf.

  1. Warum sollte der unten stehende Code \tin beiden Fällen gsubdie Dinge ersetzen? x ist eine Dummy-Datei, einige ungerade 0 am Ende.

  2. Wenn man die Linie line = $0 \n more = getline \n gsub("\t"," ")in Williamsons Antwort angreift , wird es lineanscheinend ganz normal, während moreder Wert von geknallt wird $0, oder?

Code zu Teil 1

$ gawk '{ hallo="tjena\t tjena2"; gsub("\t"," "); }; END {print hallo; gsub("\t", ""); hallo=hallo gsub("\t",""); print hallo }' x
tjena  tjena2
tjena  tjena20

Antworten:


4

Hier ist ein AWK-Skript, das lange Zeilen umschließt und die verbleibenden sowie kurze Zeilen neu umschließt:

awk -v WIDTH=72 '
{
    gsub("\t"," ")
    $0 = line $0
    while (length <= WIDTH) {
        line = $0
        more = getline
        gsub("\t"," ")
        if (more)
            $0 = line " " $0
        else
            $0 = line
            break
    }
    while (length >= WIDTH) {
        print substr($0,1,WIDTH)
        $0 = substr($0,WIDTH+1)
    }
    line = $0 " "
}

END {
    print
}
'

In CPAN ist ein Perl-Skript verfügbar, mit dem Text sehr gut neu formatiert werden kann. Es heißt paradj ( einzelne Dateien ). Um eine Silbentrennung durchzuführen, benötigen Sie ebenfalls TeX::Hyphen.

SWITCHES
--------
The available switches are:

--width=n (or -w=n or -w n)
    Line width is n chars long

--left (or -l)
    Output is left-justified (default)

--right (or -r)
    Output is right-justified

--centered (or -c)
    Output is centered

--both (or -b)
    Output is both left- and right-justified

--indent=n (or -i=n or -i n)
    Leave n spaces for initial indention (defaults to 0)

--newline (or -n)
    Insert blank lines between paragraphs

--hyphenate (or -h)
    Hyphenate word that doesn't fit on a line

Hier sind einige Änderungen, die ich vorgenommen habe, um eine Option für den linken Rand zu unterstützen:

12c12
< my ($indent, $newline);
---
> my ($indent, $margin, $newline);
15a16
>   "margin:i" => \$margin,
21a23
> $margin = 0 if (!$margin);
149a152
>     print " " x $margin;
187a191,193
>   print "--margin=n (or -m=n or -m n)  Add a left margin of n ";
>   print "spaces\n";
>   print "                                (defaults to 0)\n";

Übrigens habe ich Gilles 'Skript aufgehoben, um es als Teil von mir zu verwenden.
Bis auf weiteres angehalten.

13

Awk nicht benutzen

Ich verstehe, dass dies nur ein Teil eines größeren Problems ist, das Sie lösen awkmöchten, oder einfach ein Versuch, awk besser zu verstehen, aber wenn Sie wirklich nur Ihre Zeilenlänge auf 72 Spalten halten möchten, gibt es ein viel besseres Werkzeug.

Das fmtTool wurde speziell für diese Zwecke entwickelt:

fmt --width=72 filename

fmtIch werde mich auch bemühen, die Zeilen an vernünftigen Stellen zu brechen, um die Ausgabe besser lesbar zu machen. Auf der infoSeite finden Sie weitere Informationen zu fmt"angemessenen Orten".


GNU fmt unterstützt keine Multibyte-Codierungen, widthdh Bytes, keine Zeichen.
Phillip Kovalev

4
macOS Benutzer können verwendenfold -s -w 72
Edward Loveall

@EdwardLoveall foldfunktioniert auch auf GNU-Systemen (wird mit GNU geliefert coreutils).
Heemayl

3

Awk ist eine Turing-vollständige Sprache und keine besonders verschleierte Sprache, daher ist es einfach genug, Zeilen abzuschneiden. Hier ist eine einfache imperative Version.

awk -v WIDTH=72 '
{
    while (length>WIDTH) {
        print substr($0,1,WIDTH);
        $0=substr($0,WIDTH+1);
    }
    print;
}
'

Wenn Sie Zeilen zwischen Wörtern abschneiden möchten, können Sie sie in awk codieren. Das Erkennen von Wörtern ist jedoch nicht trivial (aus Gründen, die mehr mit natürlichen Sprachen als mit algorithmischen Schwierigkeiten zu tun haben). Viele Systeme haben ein Dienstprogramm namens fmt, das genau das tut.


Heh, ich habe meine Antwort so bearbeitet, dass sie diese beim Schreiben Ihrer Antwort enthält. Ich denke, ich werde nur meine Änderungen entfernen. Ich wünschte wirklich, ich könnte sehen, wann jemand anderes eine Antwort schrieb.
Steven D

1
Genau genommen schneidet Ihr Skript keine Zeilen ab. Vielmehr werden lange Zeilen umbrochen, der Rest jedoch nicht erneut.
Bis auf weiteres angehalten.

2

Hier ist eine Awk-Funktion, die Leerzeichen aufbricht:

function wrap(text,   q, y, z) {
  while (text) {
    q = match(text, / |$/); y += q
    if (y > 72) {
      z = z RS; y = q - 1
    }
    else if (z) z = z FS
    z = z substr(text, 1, q - 1)
    text = substr(text, q + 1)
  }
  return z
}

Überraschenderweise ist dies performanter als Fold oder Fmt .

Quelle


2

Sie haben gefragt, warum der awkCode Tabulatoren ausgegeben hat und woher die Null stammt.

  1. Der Code ändert die helloZeichenfolge bei den gsub()Aufrufen nicht. Mit zwei Argumenten gsub()wirkt auf $0. halloVerwenden Sie, um die Variable tatsächlich zu ändern gsub(..., ..., hallo).

  2. Sie erhalten die Null am Ende der Zeichenfolge, da gsub()die Anzahl der vorgenommenen Ersetzungen zurückgegeben wird, und an einem Punkt hängen Sie diese Zahl an den Wert von an hallo.

Mir sind mindestens drei Dienstprogramme bekannt, die speziell zum Umbrechen und Formatieren von Textabschnitten vorgesehen sind:

  1. fold, "Filter zum Falten von Linien", ein Standard-POSIX-Dienstprogramm . Es werden einfach Zeilenumbrüche eingefügt und kein Text neu geflossen.

  2. fmt, "einfacher Textformatierer", der häufig auch standardmäßig auf Unix-Systemen installiert wird und ein bisschen schlauer ist als foldbeim erneuten Abfließen von Absätzen.

  3. par, " Filter zum Neuformatieren von Absätzen ", der zusätzliche Funktionen zum Erkennen von Absatzpräfixen und -suffixen bietet (z. B. einen Text mit einem ASCII-Feld oder Kommentare in einem Teil des Quellcodes) und Einrückungen und hängende Einrückungen ein gutes Stück besser verarbeitet als fmt.


0

Wenn Sie gensub verwenden, um foldSemantik zu erhalten , können Sie etwas in der Art von ausführen

awk '{printf gensub("(.{0,72})","\\1\n","g")}' 
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.