【问题标题】:Align columns against one another by row按行将列相互对齐
【发布时间】:2016-03-17 03:15:16
【问题描述】:

假设一个文件包含三列字符串。

> cat file
foo foo bar
bar baz
baz qux
qux

bash 中的哪些命令(如果有)可用于将这些列逐行对齐?正确的输出如下所示:

> sought_command file
foo foo
bar     bar
baz baz
qux qux 

【问题讨论】:

  • 如果同一列中出现两个相同的单词怎么办?
  • bar bar 的情况下为什么会有多余的空间?
  • @anishsane 我认为 OP 想要的是将相同的单词放在同一行,同时保留它们的“列”。
  • ^^ 哦,现在明白了...
  • @anishsane 用户 4ae1e1 是正确的。我正在寻找以这样一种方式对齐列的代码,即每行最终包含相同的单词,但保留列。

标签: string bash text-alignment


【解决方案1】:

使用 awk:

$ awk 'max<NF{max=NF} # Get max number of columns
    { #For every input line,
       for(i=1;i<=NF;i++){
           b[$i]++;   # Record all possible tokens, like foo, bar etc.
           a[i$i]++;  # Record their column indices
       }
    }

    END{
           for(i in b) #Get max length of all the tokens (for printing)
               if(c<length(i))
                   c=length(i); 

           for(i in b) # For each token,
           {
              for(j=1;j<=max;j++){ # For every column,
                  if(a[j i]) d = i; # Decide, if we want to print it, or left blank...
                  else d="";

                  printf "%-"(c+5)"s", d; # Print the token, or blank space
              }
              print ""; # Print newline after every tokens line.
           }
       }' test.input

foo     foo             
baz     baz             
qux     qux             
bar             bar     

关于输入与输出数据的顺序:我认为没有任何输入标记顺序,因为下面的输入数据也应该给出类似的输出。

foo foo
bar
baz baz bar
qux qux 

可以保持令牌首次出现的顺序。例如在上述(重新排序)的情况下,它将是 foo、bar、baz、qux。

$ awk 'max<NF{max=NF} # Get max number of columns
{ #For every input line,
    for(i=1;i<=NF;i++){

        if(!b[$i]++)
            token[j++]=$i;
        a[i$i]++;  # Record their column indices
    }
}

END{
    for(i in b) #Get max length of all the tokens (for printing)
        if(max_len<length(i))
            max_len=length(i); 

    PROCINFO["sorted_in"] = "@ind_num_asc";

    for(i in token) { # For each token,
        for(j=1;j<=max;j++){ # For every column,
            if(a[j token[i]]) d = token[i]; # Decide, if we want to print it, or left blank...
            else d="";

            printf "%-"(max_len+5)"s", d; # Print the token, or blank space
        }
        print ""; # Print newline after every tokens line.
    }
}' test.input.reordered

foo     foo             
bar             bar     
baz     baz             
qux     qux             

【讨论】:

  • 哇!它按预期工作。这是一些密集的 awk 代码。我向你脱帽致敬!
  • 仔细查看您的代码,我注意到未保持行的原始顺序。按照这个顺序,第二行应该是“bar”而不是“baz”。维持原有秩序需要什么?
  • 如果你的代码输出保存到变量out,那么下面的代码会重新建立原来的行序:for i in $(awk '{print $1}' file); do grep ^$i out; done
  • 没有原始的行顺序,因为原始数据只是一个模式。查看编辑。
猜你喜欢
  • 1970-01-01
  • 2012-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-21
相关资源
最近更新 更多