AWK: encapsuler les lignes à 72 caractères

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

c'est-à-dire que je veux l'ajouter \naprès 72 caractères et continuer, donc au début, vous devrez peut-être supprimer tous les \ns et les ajouter. Cela peut être plus facile avec un autre outil, mais essayons de awk.

[Mise à jour]

Williamson a fourni la bonne réponse, mais une aide était nécessaire pour la lire. Je divise le problème en plusieurs parties avec des exemples plus simples, ci-dessous.

  1. Pourquoi le code ci-dessous s'imprime \tdans les deux cas, gsubdevrait remplacer les choses? x est un fichier factice, un 0 impair à la fin.

  2. Attaquer la ligne line = $0 \n more = getline \n gsub("\t"," ")dans la réponse de Williamson , lineobtient apparemment toute la sortie tout en moreobtenant une valeur sautée $0, non?

Code à la partie 1

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

Réponses:

4

Voici un script AWK qui encapsule les lignes longues et reconditionne les restes ainsi que les lignes courtes:

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

Il y a un script Perl disponible sur CPAN qui fait un très bon travail de reformatage de texte. Cela s'appelle paradj ( fichiers individuels ). Pour faire la césure, vous aurez également besoin 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

Voici quelques différences que j'ai apportées pour prendre en charge une option de marge gauche:

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";
En pause jusqu'à nouvel ordre.
la source
Au fait, j'ai levé le script de Gilles pour l'utiliser dans le mien.
pause jusqu'à nouvel ordre.
13

Ne pas utiliser awk

Je comprends que cela peut simplement être une partie d'un problème plus vaste que vous essayez de résoudre en utilisant awkou simplement une tentative de mieux comprendre awk, mais si vous voulez vraiment garder votre longueur de ligne à 72 colonnes, il existe un bien meilleur outil.

L' fmtoutil a été conçu spécifiquement dans cet esprit:

fmt --width=72 filename

fmtessaiera également de briser les lignes à des endroits raisonnables, ce qui rendra la sortie plus agréable à lire. Voir la infopage pour plus de détails sur ce que l'on fmtconsidère comme des «endroits raisonnables».

Steven D
la source
GNU fmt ne prend pas en charge les encodages multi-octets, widthsignifie des octets, pas des caractères.
Phillip Kovalev
4
Les utilisateurs de macOS peuvent utiliserfold -s -w 72
Edward Loveall
@EdwardLoveall foldfonctionnera également sur les systèmes GNU (livré avec GNU coreutils).
heemayl
3

Awk est un langage complet de Turing, et pas particulièrement obscur, il est donc assez facile de tronquer des lignes. Voici une version impérative simple.

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

Si vous voulez tronquer les lignes entre les mots, vous pouvez le coder en awk, mais la reconnaissance des mots n'est pas triviale (pour des raisons ayant plus à voir avec les langues naturelles qu'avec des difficultés algorithmiques). De nombreux systèmes ont un utilitaire appelé fmtqui fait exactement cela.

Gilles 'SO- arrête d'être méchant'
la source
Hé, je modifiais ma réponse pour l'inclure pendant que vous écriviez la vôtre. Je pense que je vais juste supprimer mes modifications. J'aimerais vraiment pouvoir voir quand quelqu'un d'autre a écrit une réponse.
Steven D
1
À strictement parler, votre script ne tronque pas les lignes; au lieu de cela, il encapsule de longues lignes, mais ne reconditionne pas le reste.
pause jusqu'à nouvel ordre.
2

Voici une fonction Awk qui se casse sur les espaces:

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
}

Étonnamment, c'est plus performant que le pli ou le fmt .

La source

Steven Penny
la source
2

Vous avez demandé pourquoi le awkcode a émis des onglets et d'où vient le zéro.

  1. Le code ne modifie pas la hellochaîne avec les gsub()appels. Avec deux arguments, gsub()agit $0. Pour réellement modifier la hallovariable, utilisez gsub(..., ..., hallo).

  2. Vous obtenez le zéro à la fin de la chaîne car gsub()renvoie le nombre de substitutions effectuées et à un moment donné, vous ajoutez ce nombre à la valeur de hallo.

Je connais au moins trois utilitaires spécialement conçus pour habiller et formater les paragraphes de texte:

  1. fold, "filtre pour lignes de pliage", qui est un utilitaire POSIX standard . Il insère simplement les nouvelles lignes et ne redistribue pas le texte.

  2. fmt, "simple text formatter", qui est également souvent installé sur les systèmes Unix par défaut et un peu plus intelligent que foldlorsqu'il s'agit de redistribuer des paragraphes.

  3. par, " filtre pour reformater les paragraphes ", qui a des capacités supplémentaires pour détecter les préfixes et suffixes de paragraphe (comme un texte avec une boîte ASCII autour, ou des commentaires dans un peu de code source), et gère les indentations et les retraits suspendus un peu mieux que fmt.

Kusalananda
la source
0

En utilisant Gensub, pour obtenir la foldsémantique, vous pouvez exécuter quelque chose dans le sens de

awk '{printf gensub("(.{0,72})","\\1\n","g")}' 
JJoao
la source