AWK:将行换成72个字符


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

即我希望它\n在72个字符之后添加并继续,因此最初您可能需要删除所有single \n并将其添加。使用其他工具可能更容易一些,但让我们尝试一下awk。

[更新]

威廉姆森提供了正确的答案,但需要一些帮助才能阅读。我在下面用更简单的示例将问题分为几部分。

  1. 为什么\t在两种情况下都显示下面的代码,gsub应该替换掉?x是一个虚拟文件,结尾处为奇数0。

  2. line = $0 \n more = getline \n gsub("\t"," ")威廉姆森的答复中上线,line显然得到整个标准输出,而more获得的弹出值是$0吗?

编写第1部分的代码

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

Answers:


4

这是一个AWK脚本,它包装长行并重新包装其余部分和短行:

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

CPAN上有一个Perl脚本,可以很好地重新格式化文本。它称为paradj单个文件)。为了进行断字,您还需要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

这是我为支持左边距选项所做的一些更改的区别:

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

顺便说一句,我取消了Gilles的剧本以用作我的一部分。
暂停,直到另行通知。

13

不使用awk

我理解这可能只是你正在试图用解决一个更大问题的一部分awk或者干脆试图更好地理解awk的,但如果你真的只是想你的线路长度保持到72列,有很多更好的工具。

fmt工具在设计时特别考虑了这一点:

fmt --width=72 filename

fmt也将努力在合理的位置打破界限,使输出更易于阅读。有关认为“合理地点”的info更多详细信息,请参见页面fmt


GNU fmt不支持多字节编码,width表示字节而不是字符。
菲利普·科瓦列夫

4
macOS用户可以使用fold -s -w 72
Edward Loveall '16年

@EdwardLoveall fold也将在GNU系统上运行(GNU附带coreutils)。
heemayl

3

Awk是一种图灵完备的语言,并不是一种特别混淆的语言,因此截断行很容易。这是一个简单的命令式版本。

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

如果要截断单词之间的行,可以用awk对其进行编码,但是识别单词并不是一件容易的事(因为与自然语言有关的原因多于算法上的困难)。许多系统都有一个称为的实用程序fmt


嘿,我正在编辑我的答案,以便在您编写自己的答案时将其包括在内。我想我只会删除我的修改。我真的希望我能看到别人写答案的时间。
史蒂文D

1
严格来说,您的脚本不会截断行;而是包装长行,但不重新包装其余部分。
暂停,直到另行通知。

2

这是一个在空格处中断的Awk函数:

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
}

令人惊讶的是,它比foldfmt性能更高。

资源


2

您问为什么awk代码发出制表符,零从何而来。

  1. 该代码不会hello使用gsub()调用修改字符串。有两个参数,gsub()作用于$0。要实际修改hallo变量,请使用gsub(..., ..., hallo)

  2. 您会在字符串的末尾得到零,因为它gsub()返回了要进行的替换的数目,并在某一点将此数字附加到的值上hallo

我知道至少有三个实用程序专门用于包装和格式化文本段落:

  1. fold,“折叠线过滤器”,这是标准的POSIX实用程序。它仅插入换行符,而不重排文本。

  2. fmt,即“简单文本格式化程序”,它通常也默认安装在Unix系统上,比重排fold段落要聪明得多。

  3. par,“ 用于重新格式化段落的过滤器 ”,它具有检测段落前缀和后缀(例如带有ASCII框的文本或一些源代码中的注释)的附加功能,并且可以更好地处理缩进和悬挂缩进比fmt


0

使用gensub,为了获得fold语义,您可以沿着

awk '{printf gensub("(.{0,72})","\\1\n","g")}' 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.