剪切 CSV 中的 int 数组列而不剪切另一个 varchar 数组

剪切 CSV 中的 int 数组列而不剪切另一个 varchar 数组

我有一个 CSV,它看起来像

details.csv

1,2,3,4,5,2015-07-30 23:17:12,2015-07-30 23:39:12,103.4,104.2,1.2,"{1,2,3}",{NORMAL},1,2,
2,2,6,4,5,2015-07-30 12:17:12,2015-07-30 12:39:12,103.4,104.2,1.8,"{4,5,6,7,8,9}",{BOOKING},1,2,
3,2,3,4,9,2015-07-30 10:17:12,2015-07-30 10:39:12,103.4,104.2,1.9,"{1,9}","{NORMAL,BOOKING}",1,2,

这里 15 列为空,12 列在为单个值时没有引号({预订}) 并在具有多个值时加引号(“{预订,正常}”)。

由此我想删除 11 列,它是一个 int 数组并且没有固定大小。所以输出看起来像

mod_details.csv
1,2,3,4,5,2015-07-30 23:17:12,2015-07-30 23:39:12,103.4,104.2,1.2,{NORMAL},1,2,
2,2,6,4,5,2015-07-30 12:17:12,2015-07-30 12:39:12,103.4,104.2,1.8,{BOOKING},1,2,
3,2,3,4,9,2015-07-30 10:17:12,2015-07-30 10:39:12,103.4,104.2,1.9,"{NORMAL,BOOKING}",1,2,

所以我尝试:

sed 's/,"{.*}"//' details.csv > mod_details.csv

但问题是我得到的输出为

mod_details.csv
1,2,3,4,5,2015-07-30 23:17:12,2015-07-30 23:39:12,103.4,104.2,1.2,{NORMAL},1,2,
2,2,6,4,5,2015-07-30 12:17:12,2015-07-30 12:39:12,103.4,104.2,1.8,{BOOKING},1,2,
3,2,3,4,9,2015-07-30 10:17:12,2015-07-30 10:39:12,103.4,104.2,1.9,1,2,

它还删除了第 12 列值,该值具有多个值,因为它也有引号。如有任何帮助,我们将不胜感激。提前致谢。

答案1

事实上,这并不是特别困难。您只需要使用比以下更具体的模式{.*}

sed 's/"{\([0-9],\)\+[0-9]}",//' details.csv

答案2

作为寻找答案的一步,您可能会发现以下 shell 函数很有帮助。我编写它是为了在命令行上以漂亮的“漂亮”布局查看 CSV。

注意它删除带引号的逗号和带引号的换行符(以及带引号的双引号),这可能不是您想要的,但对于快速查看并使列正确排列很有用。

excel() {
    sed -E -e ':t' -e '/^[^"]*("[^"]*"[^"]*)*$/!{N;s/\n//;bt' -e'}' "$@" |
      awk -F\" -v OFS= 'NF>1 {for (i=2;i<=NF;i+=2) gsub(/,/, "", $i)} 1' |
      sed 's/,/,"/g' | column -ts, | tr -d '"' | less -S
}

答案3

使用csvkit

$ csvcut -C 11 details.csv
1,2,3,4,5,2015-07-30 23:17:12,2015-07-30 23:39:12,103.4,104.2,1.2,{NORMAL},1,2,
2,2,6,4,5,2015-07-30 12:17:12,2015-07-30 12:39:12,103.4,104.2,1.8,{BOOKING},1,2,
3,2,3,4,9,2015-07-30 10:17:12,2015-07-30 10:39:12,103.4,104.2,1.9,"{NORMAL,BOOKING}",1,2,

答案4

将每一行拆分为数组"作为分隔符是一种更简单的方法。然后,您的 int 数组将成为数组的元素 1,我们可以将其设置为空字符串,下一个(元素 2)将在其末尾附加额外的逗号,因此我们可以提取该起始的子字符串从第二个字符开始。现在,我们需要以{NORMAL,BOOKING}某种方式处理将双引号返回到该部分。使用分割线"作为分隔符,这也得到了处理,因为该行将具有字段 3。如果是其他行,则不再有引号,因此我们的项目数组将仅包含索引 2 之前的项目。如果有索引 #3 我们知道我们必须引用它。

下面的 Perl 单行代码的作用与上面描述的完全一样:

$ perl -F'"' -lane '$F[1]="";$F[2]=substr($F[2],1);$F[3]= "\"" . $F[3] . "\"" if $F[3];print @F' inpu>
1,2,3,4,5,2015-07-30 23:17:12,2015-07-30 23:39:12,103.4,104.2,1.2,{NORMAL},1,2,
2,2,6,4,5,2015-07-30 12:17:12,2015-07-30 12:39:12,103.4,104.2,1.8,{BOOKING},1,2,
3,2,3,4,9,2015-07-30 10:17:12,2015-07-30 10:39:12,103.4,104.2,1.9,"{NORMAL,BOOKING}",1,2,

相关内容