AWK: bungkus baris menjadi 72 karakter

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

yaitu saya ingin menambahkan \nsetelah 72 karakter dan melanjutkan, jadi pada awalnya Anda mungkin perlu menghapus semua \ns dan menambahkannya. Mungkin lebih mudah lebih mudah dengan alat lain tetapi mari kita coba untuk awk.

[Memperbarui]

Williamson memberikan jawaban yang benar tetapi perlu bantuan untuk membacanya. Saya memecah masalah menjadi beberapa bagian dengan contoh sederhana, di bawah ini.

  1. Mengapa kode di bawah ini mencetak \tdalam kedua kasus, gsubharus menggantikan barang? x adalah file dummy, beberapa 0 aneh di akhir.

  2. Menyerang garis line = $0 \n more = getline \n gsub("\t"," ")di balasan Williamson , linetampaknya mendapat stdout seluruh saat moremendapat nilai muncul $0, kan?

Kode ke bagian 1

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

Jawaban:

4

Berikut ini adalah skrip AWK yang membungkus garis panjang dan membungkus ulang sisa-sisa serta garis pendek:

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

Ada skrip Perl yang tersedia di CPAN yang melakukan pekerjaan yang sangat bagus untuk memformat ulang teks. Ini disebut paradj ( file individual ). Untuk melakukan tanda hubung, Anda juga perlu 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

Berikut adalah perbedaan dari beberapa perubahan yang saya buat untuk mendukung opsi margin kiri:

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";
Dijeda sampai pemberitahuan lebih lanjut.
sumber
Ngomong-ngomong, aku mengangkat naskah Gilles untuk digunakan sebagai bagian dari milikku.
Dijeda sampai pemberitahuan lebih lanjut.
13

Tidak menggunakan awk

Saya mengerti ini mungkin hanya salah satu bagian dari masalah yang lebih besar yang Anda coba pecahkan menggunakan awkatau hanya upaya untuk memahami awk lebih baik, tetapi jika Anda benar-benar hanya ingin menjaga panjang garis Anda menjadi 72 kolom, ada alat yang jauh lebih baik.

The fmtalat dirancang dengan khusus ini dalam pikiran:

fmt --width=72 filename

fmtjuga akan berusaha keras untuk memecahkan garis di tempat-tempat yang wajar, membuat output lebih bagus untuk dibaca. Lihat infohalaman untuk detail lebih lanjut tentang apa yang fmtdianggap "tempat yang masuk akal."

Steven D
sumber
GNU fmt tidak mendukung penyandian multibyte, widthberarti byte, bukan karakter.
Phillip Kovalev
4
pengguna macOS dapat menggunakanfold -s -w 72
Edward Loveall
@EdwardLoveall juga foldakan bekerja pada sistem GNU (dilengkapi dengan GNU coreutils).
heemayl
3

Awk adalah bahasa Turing-lengkap, dan bukan yang sangat membingungkan, jadi cukup mudah untuk memotong garis. Berikut adalah versi imperatif langsung.

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

Jika Anda ingin memotong garis di antara kata-kata, Anda dapat membuat kode dalam awk, tetapi mengenali kata-kata adalah hal yang tidak sepele (karena alasan lebih banyak berhubungan dengan bahasa alami daripada kesulitan algoritmik). Banyak sistem memiliki utilitas yang disebut fmtyang tidak hanya itu.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Heh, saya sedang mengedit jawaban saya untuk memasukkan ini saat Anda menulis milik Anda. Saya pikir saya hanya akan menghapus suntingan saya. Saya benar-benar berharap bisa melihat ketika ada orang lain yang menulis jawaban.
Steven D
1
Sebenarnya, skrip Anda tidak memotong garis; melainkan membungkus garis panjang, tetapi tidak membungkus sisanya.
Dijeda sampai pemberitahuan lebih lanjut.
2

Berikut adalah fungsi Awk yang memecah spasi:

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
}

Anehnya ini lebih performan daripada lipat atau fmt .

Sumber

Steven Penny
sumber
2

Anda bertanya mengapa awkkode tersebut memancarkan tab dan dari mana nol berasal.

  1. Kode tidak mengubah hellostring dengan gsub()panggilan. Dengan dua argumen, gsub()bertindaklah $0. Untuk benar-benar memodifikasi hallovariabel, gunakan gsub(..., ..., hallo).

  2. Anda mendapatkan nol di akhir string karena gsub()mengembalikan jumlah pergantian yang dibuat, dan pada satu titik Anda menambahkan nomor ini ke nilai hallo.

Saya mengetahui setidaknya tiga utilitas yang khusus untuk membungkus dan memformat paragraf teks:

  1. fold, "filter untuk garis lipat", yang merupakan utilitas POSIX standar . Itu hanya menyisipkan baris baru dan tidak merefleksikan teks.

  2. fmt, "pemformat teks sederhana", yang juga sering dipasang pada sistem Unix secara default dan sedikit lebih pintar daripada foldketika harus merefleksikan paragraf.

  3. par, " filter untuk memformat ulang paragraf ", yang memiliki kemampuan tambahan untuk mendeteksi awalan paragraf dan sufiks (seperti teks dengan kotak ASCII di sekitarnya, atau komentar dalam sedikit kode sumber), dan menangani lekukan dan lekukan indentasi agak lebih baik dari fmt.

Kusalananda
sumber
0

Menggunakan gensub, untuk mendapatkan foldsemantik, Anda bisa menjalankan sesuatu di sepanjang baris

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