帮助将平面文件读入 unix 并输出为简化的 csv 格式,以便导入到 Excel 中

帮助将平面文件读入 unix 并输出为简化的 csv 格式,以便导入到 Excel 中

我有一个文本文件,其中的数据以下面的格式写入,有数千行。

  1. 新记录始终以 WHATEVER.RDNDISPLAY 或 WHATEVER.DSPLY_NAME 开头。
  2. 记录的名称是 WHATEVER
  3. 该行以 " 结尾,后跟空白,表示没有数据或一些文本、日期或字符串或数字 +100 或 -100
  4. 忽略下面的空格,因为没有,这只是看到我可以在这个网站上正确显示它。因此平面文件的每条记录有数千行。

方案

  Field separator
       v           v quote followed by blank or data  (numbers or text or even + or -)
TEST_AP.RDNDISPLAY "
   ^       ^ Field Name
Record name

例子

---------------
TEST_AB.RDNDISPLAY "
TEST_AB.DSPLY_NAME "
TEST_AB.TIMACT "
TEST_AB.NETCHNG_1 "
TEST_AB.TRADE_DATE "
TEST_AB.ACTIV_DATE "
TEST_AB.BID "
TEST_AB.ASK "
TEST_AB.MATUR_DATE "
TEST_AB.COUPN_RATE "
TEST_AB.MID_PRICE "
TEST_AB.MKT_MKR_NM "
TEST_AB.RECORDTYPE "
TEST_AB.SETTLEDATE "
TEST_AB.BID_YIELD "
TEST_AB.ASK_YIELD "
TEST_AB.GEN_VAL1 "
TEST_AB.GEN_VAL2 "
TEST_AB.GEN_VAL3 "
TEST_AB.GEN_VAL4 "
TEST_AB.SPARE_NM1 "
TEST_AB.SPARE_NM2 "
TEST_AB.SPARE_NM3 "
TESTRICU=L.DSPLY_NAME "TEST
TESTRICU=L.TIMACT "
TESTRICU=L.TRDPRC_1 "
TESTRICU=L.CURRENCY "GBP
TESTRICU=L.TRADE_DATE "
TESTRICU=L.TRDTIM_1 "
TESTRICU=L.OPEN_PRC "
TESTRICU=L.HST_CLOSE "
TESTRICU=L.BID "
TESTRICU=L.ASK "0
TESTRICU=L.BIDSIZE "
TESTRICU=L.ASKSIZE "
TESTRICU=L.YIELD "
TESTRICU=L.PERATIO "
TESTRICU=L.PCTCHNG "
TESTRICU=L.CLOSE_BID "
TESTRICU=L.CLOSE_ASK "
TESTRICU=L.STRIKE_PRC "
TESTRICU=L.MATUR_DATE "31 Dec 1906
TESTRICU=L.COUPN_RATE "+4
TESTRICU=L.OFFCL_CODE "1003
TESTRICU=L.HSTCLSDATE "
TESTRICU=L.BOND_TYPE "
TESTRICU=L.BCKGRNDPAG "
TESTRICU=L.ISSUE_DATE "01 Jan 2004
TESTRICU=L.PUTCALLIND "
TESTRICU=L.NAVALUE "
TESTRICU=L.NAV_NETCHN "
TESTRICU=L.MID_PRICE "
TESTRICU=L.EUROCLR_NO "
TESTRICU=L.CEDEL_NO "
TESTRICU=L.VALOREN_NO "100
TESTRICU=L.NAVDATE "
TESTRICU=L.NAVALUE_1 "
TESTRICU=L.NAVDAT_1 "
TESTRICU=L.PRTY_PRICE "
TESTRICU=L.ISSUE_PRC "

我希望能够以表格格式提取该文件,该文件可以以列格式读入 Excel,并在行中填充数据值。所以输出看起来像

RECORDNAME       RDNDISPLAY  DSPLY_NAME CURRENCY TIMACT NETCHNG_1 TRADE_DATE ACTIV_DATE BID ASK MATUR_DATE COUPN_RATE OFFCL_CODE ISSUE_DATE VALOREN_NO  .... so on
TEST_AB          ;
TESTRICU=L       ;          ;TEST      ;  GBP    ;       ;             ;             ;  ;   0   31 Dec 1906 ;  +4      ; 1003    ;  01 Jan 2004 ; 100     .... so on

因此,代码可能会查找每个可能的字段名称,然后再次读取文件,搜索 RDNDISPLAY 或 DSPLY_NAME 以了解记录的开头和结尾(另一个记录的开头)提取记录名称(例如,无论什么)并在每个字段下以行格式放入字段标题。对每条记录执行此操作,如果文件中不存在原始名称,则替换为 ;这样一旦导入到excel中就可以轻松完成。

答案1

CSV 有一些棘手的问题:字段包含嵌入的字段分隔符,或者字段包含嵌入的引号。我在您的示例数据中添加了 2 行:

TEST_AB.foo " with "embedded quotes" here
TESTRICU=L.foo " with an inner; semicolon

一个可怕的 Perl 解决方案是:将其保存在名为“text2csv.sh”的文件中

#!/bin/sh
perl -lne '
      @F = split /\s*"\s*/, $_, 2;
      ($record, $field) = split /\./, $F[0];
      $fields{$field} = 1;
      $records{$record} = 1;
      $data{$record}{$field} = $F[1];
  } END {
      print join ";", "RECORDNAME", keys %fields;
      for my $rec (keys %records) {
          print join";", $rec, map {
                                   $q=0;
                                   if (/"/) {s/\"/\"\"/g; $q=1}
                                   if (/;/) {$q=1}
                                   $q ? qq{"$_"} : $_
                               } @{$data{$rec}}{keys %fields};
      }
' "$1" > "$1.csv"

并像这样运行它:

sh text2csv.sh /path/to/myfile.txt
cat /path/to/myfile.txt.csv
RECORDNAME;PERATIO;NAVALUE_1;ISSUE_PRC;BCKGRNDPAG;GEN_VAL2;SPARE_NM2;GEN_VAL3;COUPN_RATE;DSPLY_NAME;CLOSE_BID;NAVALUE;VALOREN_NO;TRDTIM_1;PRTY_PRICE;ISSUE_DATE;RECORDTYPE;OFFCL_CODE;MID_PRICE;BID;TRDPRC_1;ASK;ACTIV_DATE;STRIKE_PRC;HSTCLSDATE;ASK_YIELD;MATUR_DATE;NAV_NETCHN;NAVDATE;PCTCHNG;TRADE_DATE;BIDSIZE;NAVDAT_1;ASKSIZE;MKT_MKR_NM;foo;OPEN_PRC;NETCHNG_1;BID_YIELD;RDNDISPLAY;YIELD;CURRENCY;TIMACT;GEN_VAL1;HST_CLOSE;PUTCALLIND;CLOSE_ASK;SPARE_NM3;BOND_TYPE;SPARE_NM1;SETTLEDATE;EUROCLR_NO;GEN_VAL4;CEDEL_NO
TESTRICU=L;;;;;;;;+4;TEST;;;100;;;01 Jan 2004;;1003;;;;0;;;;;31 Dec 1906;;;;;;;;;"with an inner; semicolon";;;;;;GBP;;;;;;;;;;;;
TEST_AB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"with ""embedded quotes"" here";;;;;;;;;;;;;;;;;;

答案2

如果你喜欢awk

awk -F' *[."]' '
{
    FName[$2]=1
    RName[$1]=1
    Data[$1,$2]=$3
}
END{
    printf("%s;","RECORDNAME")
    for (f in FName)
        printf ("%s;",f)
    print ""
    for (i in RName){
        printf ("%s",i)
        for (j in FName)
            printf ("%s;",Data[i,j])
        print ""
        }
}' text.file

输出:

RECORDNAME;BID_YIELD;PCTCHNG;NAVALUE_1;EUROCLR_NO;ACTIV_DATE;MKT_MKR_NM;PRTY_PRICE;NAV_NETCHN;ASKSIZE;TRDTIM_1;HST_CLOSE;CLOSE_BID;SPARE_NM1;CURRENCY;SPARE_NM2;SPARE_NM3;TRDPRC_1;NAVDATE;DSPLY_NAME;CLOSE_ASK;OPEN_PRC;MATUR_DATE;BCKGRNDPAG;STRIKE_PRC;OFFCL_CODE;ASK_YIELD;ISSUE_PRC;VALOREN_NO;BOND_TYPE;ISSUE_DATE;PUTCALLIND;RDNDISPLAY;BID;MID_PRICE;COUPN_RATE;RECORDTYPE;ASK;NAVALUE;TIMACT;YIELD;NETCHNG_1;PERATIO;SETTLEDATE;HSTCLSDATE;NAVDAT_1;GEN_VAL1;GEN_VAL2;CEDEL_NO;GEN_VAL3;GEN_VAL4;BIDSIZE;TRADE_DATE;
TEST_AB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TESTRICU=L;;;;;;;;;;;;;GBP;;;;;TEST;;;31 Dec 1906;;;1003;;;100;;01 Jan 2004;;;;;+4;;0;;;;;;;;;;;;;;;;

相关内容