如何将空格分隔的单词列表折叠成适合终端宽度的表格列

如何将空格分隔的单词列表折叠成适合终端宽度的表格列

我想以表格格式输出一系列以空格分隔的单词,逐行填充,以便没有任何内容超过终端的宽度,但可以最佳地使用可用空间,如下所示:

+-----------------------------------------------+
|polite      babies      embarrass   rightful   | 
|aspiring    scandalous  mut         disgusted  |
|bell        deeply      writer      jumbled    |
|respired    craggy                             |

(该框说明了终端的宽度 - 它不是输出的一部分)

fold浮现在脑海中的命令是column这样的:

$ fold words -s -w $COLUMNS | column -t

这几乎可以工作,但输出最终比(终端宽度)更宽,$COLUMNS因为它首先在该宽度内折叠,然后拉伸空白以使它们对齐。

我需要的是两者合二为一的效果。是否有任何命令行工具(或 shell 内置工具)可以执行此操作?

答案1

看起来您需要获取所有可能的列数(从 2 到 COLUMNS/2)的总宽度,以确定每列的宽度以及可以容纳的最大列数。

perl

#! /usr/bin/perl
use List::Util qw(sum);

$/ = undef;
@word = <> =~ /\S+/g;
$max = $ENV{COLUMNS}/2;
for ($i = 0; $i <= $#word; $i++) {
  $l = length $word[$i];
  for ($c = 2; $c <= $max; $c++) {
    if ($l > $w[$c][$i%$c]) {
      $w[$c][$i%$c] = $l
    }
  }
}
for ($c = $max; $c > 1; $c--) {
  last if $c + sum(@{$w[$c]}) - 1 <= $ENV{COLUMNS}
}
if($c > 1) {
  @w = @{$w[$c]};
  for ($i = 0; $i <= $#word; $i++) {
    if (($i+1)%$c && $i < $#word) {
      printf "%-*s ", $w[$i%$c], $word[$i]
    } else {
      print "$word[$i]\n"
    }
  }
} else {
  print "$_\n" for @word
}

例子:

$ lorem -w 50 | COLUMNS=60 that-script
minima   aut     veritatis laudantium qui      voluptatem
est      nostrum quis      enim       placeat  hic
voluptas ab      ratione   sit        hic      sit
pariatur et      provident voluptas   aut      odio
aut      vero    atque     voluptatem amet     voluptatem
ipsum    iusto   omnis     tenetur    ratione  ratione
illo     ea      odit      excepturi  quisquam aut
nobis    porro   incidunt  corrupti   maxime   ad
est      sunt

对于非 ASCII 文本,请参阅获取字符串的显示宽度确定字符串的显示宽度。就像是:

#! /usr/bin/perl
use Text::CharWidth qw(mbswidth);
use List::Util qw(sum);

$/ = undef;
@word = <> =~ /\S+/g;
$max = $ENV{COLUMNS}/2;
for ($i = 0; $i <= $#word; $i++) {
  $l = mbswidth $word[$i];
  for ($c = 2; $c <= $max; $c++) {
    if ($l > $w[$c][$i%$c]) {
      $w[$c][$i%$c] = $l
    }
  }
}
for ($c = $max; $c > 1; $c--) {
  last if $c + sum(@{$w[$c]}) - 1 <= $ENV{COLUMNS}
}
if($c > 1) {
  @w = @{$w[$c]};
  for ($i = 0; $i <= $#word; $i++) {
    if (($i+1)%$c && $i < $#word) {
      printf $word[$i] . " " x ($w[$i%$c]+1-mbswidth($word[$i]))
    } else {
      print "$word[$i]\n"
    }
  }
} else {
  print "$_\n" for @word
}

答案2

要生成等距的列,您可以使用 BSDrs(也移植到 Debian 和衍生品(至少)并作为软件包提供)或 BSD column(在bsdmainutilsDebian 上的软件包中):

tr -s '[:space:]' '[ *]' | rs -w "$COLUMNS"
tr -s '[:space:]' '[\n*]' | column -xc "$COLUMNS"

示例(垂直线用于显示 60 列宽屏幕的边缘,它不是输出的一部分):

$ lorem -w 30 | tr -s '[:space:]' '[ *]' | rs -w60
earum          aspernatur     ipsa           sed            ┃
quod           sit            esse           quisquam       ┃
animi          reprehenderit  porro          et             ┃
delectus       neque          esse           quia           ┃
pariatur       amet           iste           voluptatem     ┃
provident      praesentium    et             sint           ┃
quo            animi          doloribus      veritatis      ┃
iusto          alias                                        ┃

使用rs,您可以添加选项-z来减少列之间的空间,但这不会相应地优化列数。例如,在上面,它给出(与rs -zw60):

earum      aspernatur     ipsa       sed                    ┃
quod       sit            esse       quisquam               ┃
animi      reprehenderit  porro      et                     ┃
delectus   neque          esse       quia                   ┃
pariatur   amet           iste       voluptatem             ┃
provident  praesentium    et         sint                   ┃
quo        animi          doloribus  veritatis              ┃
iusto      alias                                            ┃

代替:

earum      aspernatur   ipsa       sed    quod              ┃
sit        esse         quisquam   animi  reprehenderit     ┃
porro      et           delectus   neque  esse              ┃
quia       pariatur     amet       iste   voluptatem        ┃
provident  praesentium  et         sint   quo               ┃
animi      doloribus    veritatis  iusto  alias             ┃

它也不适用于多字节字符或 0 宽度或双宽度字符。

默认情况下,列之间至少留有 2 个空格。您可以使用 将其更改为 1 -g 1

相关内容