AWK: ngắt dòng đến 72 ký tự


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

tức là tôi muốn nó thêm \nsau 72 ký tự và tiếp tục, vì vậy ban đầu bạn có thể cần phải xóa tất cả các \ns và thêm chúng. Nó có thể dễ dàng hơn dễ dàng hơn với công cụ khác nhưng chúng ta hãy thử awk.

[Cập nhật]

Williamson cung cấp câu trả lời đúng nhưng một số trợ giúp cần thiết để đọc nó. Tôi chia vấn đề thành nhiều phần với các ví dụ đơn giản hơn, bên dưới.

  1. Tại sao mã dưới đây in \ttrong cả hai trường hợp, gsubnên thay thế mọi thứ? x là một tập tin giả, một số 0 lẻ ở cuối.

  2. Tấn công vào dòng line = $0 \n more = getline \n gsub("\t"," ")trong câu trả lời của Williamson , linedường như nhận được toàn bộ tiêu chuẩn trong khi morenhận được giá trị của $0, phải không?

Mã cho phần 1

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

Câu trả lời:


4

Dưới đây là tập lệnh AWK bao bọc các dòng dài và kết thúc lại các phần còn lại cũng như các dòng ngắn:

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ó một kịch bản Perl có sẵn trên CPAN, công việc định dạng lại văn bản rất hay. Nó được gọi là paradj ( tập tin cá nhân ). Để làm gạch nối, bạn cũng sẽ cần 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

Đây là một số khác biệt của một số thay đổi tôi đã thực hiện để hỗ trợ tùy chọn lề trái:

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

Nhân tiện, tôi đã nâng kịch bản của Gilles để sử dụng như một phần của tôi.
Tạm dừng cho đến khi có thông báo mới.

13

Không sử dụng awk

Tôi hiểu đây có thể chỉ là một phần của vấn đề lớn hơn mà bạn đang cố gắng giải quyết bằng cách sử dụng awkhoặc đơn giản là cố gắng hiểu awk tốt hơn, nhưng nếu bạn thực sự chỉ muốn giữ chiều dài dòng của mình đến 72 cột, có một công cụ tốt hơn nhiều .

Công fmtcụ này được thiết kế dành riêng cho mục đích này:

fmt --width=72 filename

fmtcũng sẽ cố gắng hết sức để ngắt các dòng ở những nơi hợp lý, làm cho đầu ra đẹp hơn để đọc. Xem infotrang để biết thêm chi tiết về những gì fmtđược coi là "địa điểm hợp lý".


GNU fmt không hỗ trợ mã hóa đa bào, widthcó nghĩa là byte, không phải ký tự.
Phillip Kovalev

4
Người dùng macOS có thể sử dụngfold -s -w 72
Edward Loveall

@EdwardLoveall foldcũng sẽ hoạt động trên các hệ thống GNU (đi kèm với GNU coreutils).
heemayl

3

Awk là một ngôn ngữ hoàn chỉnh Turing, và không phải là ngôn ngữ bị che khuất đặc biệt, vì vậy nó đủ dễ để cắt ngắn các dòng. Đây là một phiên bản mệnh lệnh đơn giản.

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

Nếu bạn muốn cắt ngắn các dòng giữa các từ, bạn có thể mã hóa nó trong awk, nhưng nhận ra các từ là không tầm thường (vì lý do có nhiều việc phải làm với ngôn ngữ tự nhiên hơn là khó khăn về thuật toán). Nhiều hệ thống có một tiện ích gọi là fmtlàm điều đó.


Heh, tôi đã chỉnh sửa câu trả lời của tôi để bao gồm điều này khi bạn đang viết của bạn. Tôi nghĩ rằng tôi sẽ xóa các chỉnh sửa của mình. Tôi thực sự ước tôi có thể nhìn thấy khi ai đó đang viết câu trả lời.
Steven D

1
Nói đúng ra, kịch bản của bạn không cắt ngắn dòng; thay vào đó, nó quấn các hàng dài, nhưng không gói lại phần còn lại.
Tạm dừng cho đến khi có thông báo mới.

2

Đây là một chức năng Awk phá vỡ không gian:

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
}

Đáng ngạc nhiên là điều này hiệu quả hơn gấp hoặc fmt .

Nguồn


2

Bạn hỏi tại sao awkmã phát ra các tab và số 0 đến từ đâu.

  1. Mã không sửa đổi hellochuỗi với các gsub()cuộc gọi. Với hai đối số, gsub()hành động trên $0. Để thực sự sửa đổi các hallobiến, sử dụng gsub(..., ..., hallo).

  2. Bạn nhận được số 0 ở cuối chuỗi vì gsub()trả về số lần thay thế được thực hiện và tại một thời điểm bạn nối số này vào giá trị của hallo.

Tôi biết ít nhất ba tiện ích dành riêng cho việc gói và định dạng các đoạn văn bản:

  1. fold, "bộ lọc cho các đường gấp", là một tiện ích POSIX tiêu chuẩn . Nó chỉ đơn giản là chèn dòng mới và không chỉnh lại văn bản.

  2. fmt, "Trình định dạng văn bản đơn giản", thường được cài đặt trên các hệ thống Unix theo mặc định và thông minh hơn một chút so với foldkhi nói về các đoạn văn bản.

  3. par, " bộ lọc để định dạng lại các đoạn ", có khả năng bổ sung để phát hiện các tiền tố và hậu tố của đoạn văn bản (chẳng hạn như một văn bản có hộp ASCII xung quanh nó, hoặc nhận xét trong một chút mã nguồn) và xử lý thụt lề và treo thụt lề tốt hơn một chút hơn fmt.


0

Sử dụng gensub, để có được foldngữ nghĩa, bạn có thể chạy một cái gì đó dọc theo dòng

awk '{printf gensub("(.{0,72})","\\1\n","g")}' 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.