【问题标题】:Convert a fixed length file to csv file将固定长度文件转换为 csv 文件
【发布时间】:2014-12-27 09:55:59
【问题描述】:

我该怎么做:

  1. 将固定长度文件转换为 csv 文件。

  2. 根据列长度从输入文件(固定长度文件)中拆分记录。

我尝试使用 'awk' 转换文件,但是由于记录中的空格,结果不正确。

输入文件:

4002000W1ABCDABCD7821 12345671LSN12301630 00000000000091640
00409164
4002000W1ABCDABCD7821 12345671LSN12301630 00000000000091640
00409164
4002000W1ABCDABCD7821 12345671LSN12301630 00000000000091640
00409164
4002000W1ABCDABCD7821 12345671LSN12301630 00000000000091640
00409164
4002000W1ABCDABCD7821 12345671LSN12301630 00000000000091640
004009164
4002000W1ABCDABCD7821 12345671LSN12301630 00000000000091640
004009164

第一条记录从4002000W1ABCDABCD7821开始,结束于 00409164

一共有6条记录。

输入文件包含表的 6 条记录。

记录有40多列,我只提到了其中的几个。

列的长度固定如下:

ABC_ID(9), def_sc(8), sde_hd(8),mln_hfg(12), ghi_jkl(13),ijk_klm(6),pqr_xyz(10)

预期输出如下:

输出文件:

ABC_ID,     def_sc, sde_hd,   mln_hfg,        ghi_jkl,     ijk_klm,  pqr_xyz
4002000W1, ABCDABCD,78211234, 56702291LSN1, 2301630000000, 000916, 4000409164
4002000W1, ABCDABCD,78211234, 56702291LSN1, 2301630000000, 000916, 4000409164
4002000W1, ABCDABCD,78211234, 56702291LSN1, 2301630000000, 000916, 4000409164
4002000W1, ABCDABCD,78211234, 56702291LSN1, 2301630000000, 000916, 4000409164
4002000W1, ABCDABCD,78211234, 56702291LSN1, 2301630000000, 000916, 4000409164
4002000W1, ABCDABCD,78211234, 56702291LSN1, 2301630000000, 000916, 4000409164

这是否可以使用 sed 命令来实现。

请提出建议。

【问题讨论】:

  • 请使用代码标签{} 编辑您的输入文件数据,就像我在输出文件上所做的那样。删除输入文件中的所有>
  • “56789071......”在哪个字符处停止? 6 条记录需要 4 列还是 6 列?

标签: unix csv awk sed


【解决方案1】:

尚不完全清楚您想要什么,但用于 FIELDWIDTHS 的 GNU awk 和多字符 RS 是一种选择:

$ awk -v RS='^$' -v FIELDWIDTHS="9 8 8 8" -v OFS=', ' '{gsub(/\n/,""); print $1, $2, $3, $4}' file
4002000W1, ABCDABCD, 78211234, 56789071

【讨论】:

  • 感谢埃德的回复。
  • But when i use the above command on my input file,i am getting the output as : 4002000W1ABCDABCD7821, 123456789071001080600W1VUF34216002902291LSN12301630, 0000000004000000000000009164000400000091645012500000000. Instead of delimiting the record as per the length specified,white spaces are getting replaced by ','。这实际上不是预期的结果。
  • @user229691 您使用的是哪个版本的awk
  • @user229691 我认为你必须安装gawk 才能使用FIELDWIDTHS
  • 感谢@HåkonHægland,安装“gawk”可以工作,但是它会从输入文件中读取一条记录。其余记录没有被读取。
【解决方案2】:
awk -v FIELDWIDTHS="9 8 8 12 13 6 10" 'NR%2{temp=$0;next;} {$0=temp$0; gsub(/ /,""); print $1,$2,$3,$4,$5,$6,$7}' OFS=','  file

输入文件:

4002000W1ABCDABCD7821 123456702291LSN1230 16300000000009164
000409164
4002000W1ABCDABCD7821 123456702291LSN1230 16300000000009164
000409164
4002000W1ABCDABCD7821 123456702291LSN1230 16300000000009164
000409164
4002000W1ABCDABCD7821 123456702291LSN1230 16300000000009164
000409164
4002000W1ABCDABCD7821 123456702291LSN1230 16300000000009164
000409164
4002000W1ABCDABCD7821 123456702291LSN1230 16300000000009164
000409164

输出文件:

4002000W1,ABCDABCD,78211234,56702291LSN1,2301630000000,000916,4000409164
4002000W1,ABCDABCD,78211234,56702291LSN1,2301630000000,000916,4000409164
4002000W1,ABCDABCD,78211234,56702291LSN1,2301630000000,000916,4000409164
4002000W1,ABCDABCD,78211234,56702291LSN1,2301630000000,000916,4000409164
4002000W1,ABCDABCD,78211234,56702291LSN1,2301630000000,000916,4000409164
4002000W1,ABCDABCD,78211234,56702291LSN1,2301630000000,000916,4000409164

要添加第一行,首先将其打印在BEGIN{...}

awk -v FIELDWIDTHS="9 8 8 12 13 6 10" 'BEGIN{print "ABC_ID,    def_sc,   sde_hd,   mln_hfg,        ghi_jkl,     ijk_klm,  pqr_xyz"} NR%2{temp=$0;next;} {$0=temp$0; gsub(/ /,""); print $1,$2,$3,$4,$5,$6,$7}' OFS=','  file

说明:

  • FIELDWIDTHS="9 8 8 12 13 6 10" 指定要打印的字段长度。
  • NR%2{temp=$0;next;} 将奇数行存储在temp 变量中(将用于连接这对行)
  • $0=temp$0 连接每一行。 $0 是当前行,temp 是当前行之前的行。
  • gsub(/ /,""); 删除空格字符。
  • print $1,$2,$3,$4,$5,$6,$7FIELDWIDTHS 打印具有预定义宽度的七个字段

【讨论】:

    【解决方案3】:

    这是一个 Perl 解决方案:

    use strict;
    use warnings;
    
    my @fmt = (9, 8, 8, 12, 13, 6, 10);
    my @head = qw(ABC_ID def_sc sde_hd mln_hfg ghi_jkl ijk_klm pqr_xyz);
    
    my $rec_len = do { my $sum; for(@fmt) { $sum += $_ }; $sum };
    
    my $fn = 'file';
    open(my $fh, '<', $fn) or die "Could not open file '$fn': $!\n";
    my $str = do {local $/ = undef; <$fh>};
    close($fh);
    $str =~ s/\s*//g;
    my $regex = join ("", map { "(.{$_})" } @fmt);
    
    my $head_fmt = join (", ", map { "%-". $_ . "s", } @fmt) . "\n";
    printf $head_fmt, @head;
    
    while ( $str =~ /(.{$rec_len})/g ) {
        my @f = $1 =~ /$regex/;
        print join(", ", @f) . "\n";
    }
    

    输出:

    ABC_ID   , def_sc  , sde_hd  , mln_hfg     , ghi_jkl      , ijk_klm, pqr_xyz   
    4002000W1, ABCDABCD, 78211234, 5671LSN12301, 6300000000000, 009164, 0004091644
    002000W1A, BCDABCD7, 82112345, 671LSN123016, 3000000000000, 091640, 0040916440
    02000W1AB, CDABCD78, 21123456, 71LSN1230163, 0000000000000, 916400, 0409164400
    2000W1ABC, DABCD782, 11234567, 1LSN12301630, 0000000000009, 164000, 4091644002
    000W1ABCD, ABCD7821, 12345671, LSN123016300, 0000000000091, 640004, 0091644002
    

    【讨论】:

    • 感谢 @Hakon 的脚本,但我需要在 shell 或 gawk 中完成。
    猜你喜欢
    • 2017-12-17
    • 1970-01-01
    • 2015-04-18
    • 2014-05-19
    • 1970-01-01
    • 2019-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多