AWK: avvolge le linee a 72 caratteri


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

cioè voglio aggiungerlo \ndopo 72 caratteri e continuare, quindi inizialmente potresti dover rimuovere tutti i singoli \ne aggiungerli. Potrebbe essere più facile essere più facile con altri strumenti, ma proviamo a risvegliare.

[Aggiornare]

Williamson ha fornito la risposta giusta ma era necessario un po 'di aiuto per leggerla. Divido il problema in parti con esempi più semplici, di seguito.

  1. Perché il codice seguente viene stampato \tin entrambi i casi, gsubdovrebbe sostituire le cose? x è un file fittizio, alla fine uno strano 0.

  2. Attaccando la linea line = $0 \n more = getline \n gsub("\t"," ")nella risposta di Williamson , lineapparentemente diventa completamente stdout mentre moreottiene il valore spuntato di $0, giusto?

Codice alla parte 1

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

Risposte:


4

Ecco uno script AWK che avvolge le linee lunghe e ri-avvolge i resti e le linee brevi:

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

C'è uno script Perl disponibile su CPAN che fa un ottimo lavoro di riformattazione del testo. Si chiama paradj ( singoli file ). Per eseguire la sillabazione, avrai anche bisogno 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

Ecco una differenza di alcune modifiche che ho apportato per supportare un'opzione del margine sinistro:

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

A proposito, ho sollevato la sceneggiatura di Gilles per usarla come parte della mia.
In pausa fino a nuovo avviso.

13

Non usando awk

Capisco che questo potrebbe essere solo una parte di un problema più grande che stai cercando di risolvere usando awko semplicemente un tentativo di comprendere meglio awk, ma se vuoi davvero solo mantenere la lunghezza della linea a 72 colonne, c'è uno strumento molto migliore.

Lo fmtstrumento è stato progettato appositamente per questo:

fmt --width=72 filename

fmtfarà anche del nostro meglio per rompere le linee in luoghi ragionevoli, rendendo l'output più piacevole da leggere. Vedi la infopagina per maggiori dettagli su ciò che fmtconsidera "luoghi ragionevoli".


GNU fmt non supporta codifiche multibyte, widthsignifica byte, non caratteri.
Phillip Kovalev,

4
gli utenti macOS possono utilizzarefold -s -w 72
Edward Loveall

@EdwardLoveall foldfunzionerà anche su sistemi GNU (viene fornito con GNU coreutils).
heemayl

3

Awk è un linguaggio completo di Turing e non particolarmente offuscato, quindi è abbastanza facile troncare le linee. Ecco una versione imperativa semplice.

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

Se vuoi troncare le linee tra le parole, puoi codificarle in awk, ma riconoscere le parole non è banale (per motivi che hanno più a che fare con i linguaggi naturali che con le difficoltà algoritmiche). Molti sistemi hanno un'utilità chiamata fmtche fa proprio questo.


Heh, stavo modificando la mia risposta per includerla mentre scrivevi la tua. Penso che rimuoverò solo le mie modifiche. Vorrei davvero poter vedere quando qualcun altro stava scrivendo una risposta.
Steven D,

1
A rigor di termini, la tua sceneggiatura non sta troncando le linee; piuttosto, sta avvolgendo le linee lunghe, ma non ri-avvolgendo il resto.
In pausa fino a nuovo avviso.

2

Ecco una funzione Awk che si rompe negli spazi:

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
}

Sorprendentemente questo è più performante di fold o fmt .

fonte


2

Hai chiesto perché il awkcodice ha emesso le schede e da dove proviene lo zero.

  1. Il codice non modifica la hellostringa con le gsub()chiamate. Con due argomenti, gsub()agisce $0. Per modificare effettivamente la hallovariabile, utilizzare gsub(..., ..., hallo).

  2. Si ottiene lo zero alla fine della stringa perché gsub()restituisce il numero di sostituzioni effettuate e ad un certo punto si aggiunge questo numero al valore di hallo.

Sono a conoscenza di almeno tre programmi di utilità specifici per il wrapping e la formattazione di paragrafi di testo:

  1. fold, "filtro per linee di piegatura", che è un'utilità POSIX standard . Inserisce semplicemente nuove righe e non ridisegna il testo.

  2. fmt, "semplice formattatore di testo", che viene spesso installato sui sistemi Unix per impostazione predefinita e un po 'più intelligente rispetto a foldquando si tratta di ridisporre i paragrafi.

  3. par, " filtro per riformattare i paragrafi ", che ha funzionalità aggiuntive per rilevare prefissi e suffissi di paragrafo (come un testo con una casella ASCII attorno ad esso, o commenti in un po 'di codice sorgente) e gestisce il rientro e appende i rientri un po' meglio di fmt.


0

Usando gensub, al fine di ottenere la foldsemantica, potresti eseguire qualcosa di simile

awk '{printf gensub("(.{0,72})","\\1\n","g")}' 
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.