有没有办法准确解析真实的 CSV 文件?

有没有办法准确解析真实的 CSV 文件?

我正在使用 bash shell。我想解析一个 CSV 文件,其中 CSV 文件观察真正的 CSV 格式。从这个线程——https://stackoverflow.com/questions/4286469/how-to-parse-a-csv-file-in-bash, 我懂了

#!/bin/bash

file_path=$1
echo $1

while IFS=, read -r ID name address zipcode
do
    echo "I got:$ID|$name|$address|$zipcode"
done < $file_path

但是,在 CSV 文件中,由于某些单元格本身可能包含逗号,因此这些项目周围有引号。所以下面的文件无法正确解析

1,1871,"222 W. Merchandise Mart Plaza, Suite 1212",60605

有没有一种方法可以修改上述脚本(或生成新脚本),从而可以准确解析 CSV 文件?

答案1

cvskit就是您所需要的:它具有针对 CSV 文件的强大 grep、cut、join 等功能。我只会使用csvformat.

在这种情况下我喜欢:

(1) 将输入数据转换为“好的”分隔符(例如:“,”到“§”),删除不必要的引号

csvformat -d § input | ...

(2) 用“好”分隔符处理数据

... | awk 'BEGIN{FS=OFS="§"} ...' | ...

(3)再次转换为CSV(“§”到“,”)必要时添加引号

csvformat -D § > final

答案2

输入文件a.csv:

1,1111,"111 W. Merchandise Mart's Plaza, Suite 1111",10101
2,2222,"222 Ben's St, Suite 222",20202

使用 python 3 解析输入文件的一个衬垫:

$ cat a.csv|python -c $'import csv,sys;reader=csv.reader(sys.stdin);\nfor row in reader: print row'

输出:

['1', '1111', "111 W. Merchandise Mart's Plaza, Suite 1111", '10101']
['2', '2222', "222 Ben's St, Suite 222", '20202']

更复杂的一行输出:

$ cat a.csv |python -c $'import csv,sys;reader=csv.reader(sys.stdin);\na=0\nb=0\nfor row in reader:\n\ta+=1\n\tprint "Column",a\n\tfor col in row:\n\t\tb+=1\n\t\tprint "\tColumn",b,":",col'
Column 1
        Column 1 : 1
        Column 2 : 1111
        Column 3 : 111 W. Merchandise Mart's Plaza, Suite 1111
        Column 4 : 10101
Column 2
        Column 5 : 2
        Column 6 : 2222
        Column 7 : 222 Ben's St, Suite 222
        Column 8 : 20202

第二行代码的可读版本:

import csv,sys;
reader=csv.reader(sys.stdin);
a=0
b=0
for row in reader:
    a+=1
    print "Column",a
    for col in row:
        b+=1
        print "    Column",b,":",col

Gnu awk(gawk):

$ cat a.csv| awk -vFPAT='[^,]*|"[^"]*"' '{for (i=1; i<=NF; i++) {print ">"$i"<"}; print ""}'
>1<
>1111<
>"111 W. Merchandise Mart's Plaza, Suite 1111"<
>10101<

>2<
>2222<
>"222 Ben's St, Suite 222"<
>20202<

答案3

我在某处有一个 awk 脚本,用于处理我见过的 Excel 输出的任何内容:可变数量的字段;字段中的逗号、换行符和双引号;即使不需要的地方也要引用字段;列标题行;修剪空白区域;回车换行转换。我需要寻找它——我认为它在几种格式之间进行了转换,大约需要 300 行(包括它自己的手册页)。还对列进行一些统计以帮助您指定 DDL。

主要问题是决定输出的格式。我选择了“|”字段用 bar 分隔,换行符用 $ 分隔,以避免将相同的问题传播到输出中。很容易使用(例如)ASCII 0x1f(单位分隔符)表示列,使用 0x1D(组分隔符)表示字段内换行符。

我可以看到对先前线程的引用,其中提到了各种工具和库。当我被锁定的关键系统困住时——无法下载,我写了这篇文章。我什至不被允许使用 C 语言,以防我破坏了他们供应商的产品,但他们承认“我可以编写脚本——你不能用它们造成任何损害。”

相关内容