AWK: quebrar linhas com 72 caracteres

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

ou seja, eu quero adicionar \ndepois de 72 caracteres e continuar, portanto, inicialmente, você pode precisar remover todos os \ns e adicioná-los. Pode ser mais fácil, mais fácil com outra ferramenta, mas vamos tentar o awk.

[Atualizar]

Williamson forneceu a resposta certa, mas foi necessária alguma ajuda para lê-la. Divido o problema em partes com exemplos mais simples, abaixo.

  1. Por que o código abaixo é impresso \tnos dois casos, gsubdeve substituir as coisas? x é um arquivo fictício, alguns 0 ímpares no final.

  2. Atacando a linha line = $0 \n more = getline \n gsub("\t"," ")na resposta de Williamson , lineaparentemente fica totalmente desatualizado, enquanto o morevalor é disparado $0, certo?

Código para a 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
Comunidade
fonte

Respostas:

4

Aqui está um script AWK que envolve linhas longas e reorganiza os demais, bem como linhas curtas:

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

Existe um script Perl disponível no CPAN que faz um ótimo trabalho de reformatação de texto. É chamado paradj ( arquivos individuais ). Para fazer a hifenização, você também precisará 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

Aqui estão algumas diferenças que eu fiz para oferecer suporte a uma opção de margem esquerda:

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";
Pausado até novo aviso.
fonte
A propósito, levantei o script de Gilles para usar como parte do meu.
Pausado até novo aviso.
13

Não está usando o awk

Entendo que isso pode ser apenas parte de um problema maior que você está tentando resolver usando awkou simplesmente uma tentativa de entender melhor o awk, mas se você realmente deseja apenas manter o comprimento da linha em 72 colunas, há uma ferramenta muito melhor.

A fmtferramenta foi projetada com isso especificamente em mente:

fmt --width=72 filename

fmttambém tentará arduamente quebrar as linhas em locais razoáveis, tornando a saída mais agradável de ler. Veja a infopágina para mais detalhes sobre o que fmtconsidera "lugares razoáveis".

Steven D
fonte
O GNU fmt não suporta codificações multibyte, widthsignifica bytes, não caracteres.
Phillip Kovalev 23/01
4
usuários MacOS pode usarfold -s -w 72
Edward Loveall
O @EdwardLoveall foldtambém funcionará em sistemas GNU (vem com o GNU coreutils).
precisa saber é
3

O awk é uma linguagem completa de Turing, e não particularmente ofuscada, por isso é fácil o suficiente para truncar linhas. Aqui está uma versão imperativa direta.

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

Se você deseja truncar linhas entre as palavras, pode codificá-las no awk, mas reconhecer as palavras não é trivial (por motivos que têm mais a ver com linguagens naturais do que com dificuldade algorítmica). Muitos sistemas têm um utilitário chamado fmtque faz exatamente isso.

Gilles 'SO- parar de ser mau'
fonte
Eu estava editando minha resposta para incluir isso enquanto você escrevia a sua. Acho que vou remover minhas edições. Eu realmente gostaria de poder ver quando alguém estava escrevendo uma resposta.
Steven D
1
Estritamente falando, seu script não está truncando linhas; em vez disso, está quebrando linhas longas, mas não envolvendo novamente o restante.
Pausado até novo aviso.
2

Aqui está uma função do Awk que quebra nos espaços:

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
}

Surpreendentemente, isso é mais eficiente do que fold ou fmt .

Fonte

Steven Penny
fonte
2

Você perguntou por que o awkcódigo emitiu guias e de onde veio o zero.

  1. O código não modifica a hellosequência com as gsub()chamadas. Com dois argumentos, gsub()atua $0. Para realmente modificar a hallovariável, use gsub(..., ..., hallo).

  2. Você obtém o zero no final da string porque gsub()retorna o número de substituições feitas e, em um ponto, você anexa esse número ao valor de hallo.

Estou ciente de pelo menos três utilitários especificamente para agrupar e formatar parágrafos de texto:

  1. fold, "filtro para linhas dobráveis", que é um utilitário POSIX padrão . Simplesmente insere novas linhas e não reflui o texto.

  2. fmt, "formatador de texto simples", que também é frequentemente instalado nos sistemas Unix por padrão e um pouco mais inteligente do que foldquando se trata de parágrafos refletidos.

  3. par, " filtro para reformatar parágrafos ", que possui recursos adicionais para detectar prefixos e sufixos de parágrafos (como um texto com uma caixa ASCII ao redor ou comentários em um pouco de código-fonte), além de lidar com indentação e indentações pendentes um pouco melhor que fmt.

Kusalananda
fonte
0

Usando o gensub, para obter foldsemântica, você pode executar algo ao longo das linhas de

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