提取列范围并通过awk重构矩阵

时间:2017-10-30 18:49:18

标签: string awk split concatenation multiple-columns

假设文本文件(file1)包含 m 字母字符串行 S S_1 S_2 ,..., S_m )。每个 S 前面都有一个简短的字母数字字符串作为条形码(此处: foo1 bar7 baz3 )。字母串 S 的长度都相同。每个 S 及其前面的条形码由空格分隔。

$ cat file1
foo1 abcdefghijklmnopqrstuvwxyz
bar7 abcdefghijklmnopqrstuvwxyz
baz3 abcdefghijklmnopqrstuvwxyz

假设第二个文件(file2)包含 n 列范围 R 的规范( R_1 R_2 ,..., R_n )。列范围在一行上并由空格分隔。每个 R_x 小于 S 。范围的组合长度(即 R_1 + R_2 + ... + R_n )也小于 S 。没有范围重叠或构成彼此的子集。

$ cat file2
2-11 14-19 23-24

关注this excellent answer,我了解我可以通过以下 awk提取所有 S 的第一个范围(即 R_1 命令,同时保持条形码正确分配:

awk 'NR==FNR{start=$1;lgth=$2;next} {print $1, substr($2,start,lgth)}' FS='-' file2 FS=' ' file1

但是,我不确定如何扩展 awk -code以遍历所有其他范围(此处: R_2 R_3 )和将每个追加到不断增长的矩阵中。

$ sought_outcome
foo1 bcdefghijknopqrswx
bar7 bcdefghijknopqrswx
baz3 bcdefghijknopqrswx

修改 为了更好地理解,这里所示的搜索输出使得连接点由空格强调:

     2-11       14-19  23-24
foo1 bcdefghijk nopqrs wx
bar7 bcdefghijk nopqrs wx
baz3 bcdefghijk nopqrs wx

2 个答案:

答案 0 :(得分:1)

awk救援!没有任何验证检查!

$ awk 'NR==FNR {printf "%s", "key"; 
                for(i=1;i<=NF;i++) 
                  {split($i,x,"-"); 
                   start[i]=x[1]; 
                   end[i]  =x[2]; 
                   printf "%s", FS $i}; 
                print ""; 
                next} 

               {printf "%s", $1; 
                for(i in start) printf "%s", FS substr($2,start[i],end[i]-start[i]+1); 
                print ""}' range file | 
  column -t


key   2-11        14-19   23-24
foo1  bcdefghijk  nopqrs  wx
bar7  bcdefghijk  nopqrs  wx
baz3  bcdefghijk  nopqrs  wx

或者,没有标题和分裂

$ awk 'NR==FNR{for(i=1;i<=NF;i++) 
                 {split($i,x,"-"); start[i]=x[1]; end[i]=x[2]}; 
                  print ""; n=NF; next}
              {printf "%s", $1 FS; 
               for(i=1;i<=n;i++) printf "%s", substr($2,start[i],end[i]-start[i]+1); print ""}' range file   column -t                        

foo1 bcdefghijknopqrswx
bar7 bcdefghijknopqrswx
baz3 bcdefghijknopqrswx

<强>更新 但是,剪切/粘贴可能更容易

$ paste -d' ' <(cut -d' ' -f1 file) <(cut -d' ' -f2 file | cut -c$(tr ' ' ',' <range))
foo1 bcdefghijknopqrswx
bar7 bcdefghijknopqrswx
baz3 bcdefghijknopqrswx

答案 1 :(得分:0)

我提出的结果几乎与@karakfas第二个脚本完全相同,但我发现他格式化代码的方式极难阅读,所以我想我还是会发布这个:

$ cat tst.awk
NR==FNR {
    for (i=1; i<=NF; i++) {
        split($i,range,/-/)
        beg[i] = range[1]
        end[i] = range[2]
    }
    numRanges = NF
    next
}
{
    printf "%s%s", $1, OFS
    for (i=1; i<=numRanges; i++) {
        printf "%s", substr($2,beg[i],(end[i]-beg[i])+1)
    }
    print ""
}

$ awk -f tst.awk file2 file1
foo1 bcdefghijknopqrswx
bar7 bcdefghijknopqrswx
baz3 bcdefghijknopqrswx