スペースで区切られた単語のリストを端末の幅に合うテーブル列に縮小する方法

スペースで区切られた単語のリストを端末の幅に合うテーブル列に縮小する方法

次のようにスペースで区切られた一連の単語をテーブル形式で出力し、1行ずつ埋め、端末の幅を超えずに利用可能なスペースを最適に活用したいと思います。

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

(ボックスは端末の幅を説明し、出力の一部ではありません)

fold思い出させる命令はcolumnこうです。

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

$COLUMNSこれはほぼうまく機能しますが、出力は最初にその幅内で縮小され、次にスペースを増やして整列するため(ターミナル幅)よりも広くなります。

私にとって必要なのは、この2つが1つにまとめられた効果です。これを実行できるコマンドラインツール(または組み込みシェル)はありますか?

答え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

同じ間隔の列を生成するには、BSDを使用できます。rs(また、Debianおよび派生製品(少なくとも)として移植されており、パッケージとして利用可能です)またはBSD columnbsdmainutilsDebianのパッケージ):

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それによって列数は最適化されません。たとえば、上記では(AND 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倍の文字には機能しません。

デフォルトでは、列の間には少なくとも2つのスペースがあります。を使用して1に変更できます-g 1

関連情報