![帮助将平面文件读入 unix 并输出为简化的 csv 格式,以便导入到 Excel 中](https://linux22.com/image/47464/%E5%B8%AE%E5%8A%A9%E5%B0%86%E5%B9%B3%E9%9D%A2%E6%96%87%E4%BB%B6%E8%AF%BB%E5%85%A5%20unix%20%E5%B9%B6%E8%BE%93%E5%87%BA%E4%B8%BA%E7%AE%80%E5%8C%96%E7%9A%84%20csv%20%E6%A0%BC%E5%BC%8F%EF%BC%8C%E4%BB%A5%E4%BE%BF%E5%AF%BC%E5%85%A5%E5%88%B0%20Excel%20%E4%B8%AD.png)
我有一个文本文件,其中的数据以下面的格式写入,有数千行。
- 新记录始终以 WHATEVER.RDNDISPLAY 或 WHATEVER.DSPLY_NAME 开头。
- 记录的名称是 WHATEVER
- 该行以 " 结尾,后跟空白,表示没有数据或一些文本、日期或字符串或数字 +100 或 -100
- 忽略下面的空格,因为没有,这只是看到我可以在这个网站上正确显示它。因此平面文件的每条记录有数千行。
方案
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;;;;;;;;;;;;;;;;