带有嵌套引用的 csv 到 tsv

带有嵌套引用的 csv 到 tsv

我需要在 bash 中将 CSV 转换为 TSV。我发现解决方案,它运行良好,但不适用于所有数据集,如下所示。

例如,对于a.txt

a,"test, part2 ""the start""",b

sed格式错误:

[ nir ]$ cat a.txt | sed -E 's/("([^"]*)")?,/\2\t/g' 
a    "test    Op. 15 ""the start"    b
#^ tab....^ tab..................^ tab

这里的问题:缺少,、额外的选项卡、额外的引号。

只是为了引用即使 python 代码格式也很糟糕:

[ nir ]$ cat a.txt | csv2tsv.py
a    "test, part2 ""the start"""    b
#^ tab..........................^ tab

这里的问题:额外的引号。

csv2tsv.py是: csv.writer(sys.stdout, dialect='excel-tab').writerows(csv.reader(sys.stdin))

真正的转换应该是这样的:

a    test, part2 "the start"    b
#^ tab......................^ tab

希望得到一些反馈如何解决这个问题bash。我在互联网上浏览了许多解决方案,但没有设法处理引号内引号上的那些引号:)

答案1

mlr

mlr -N --icsv --otsvlite cat < file.csv > file.tsv

或者:

mlr -N --c2t --quote-none cat < file.csv > file.tsv

但请注意,如果 csv 字段包含制表符,则它最终不会在输出中转义,因此会引入额外的字段。

使用 GNU sed,您可以执行相同的操作:

sed -E '
  # append next line as long as there is not an even number
  # of "s, to handle fields with newline. You can omit this line
  # if the fields are guaranteed not to contain newlines:
  :1; /^([^"]*"[^"]*")*[^"]*$/! {N;b1}

  s/$/,/
  s/(([^,"]*)|"((""|[^"])*)"),/\2\3\t/g
  s/\t$//
  s/""/"/g' < file.csv > file.tsv

假设输入是当前区域设置中的有效文本。首先sed禁用LC_ALL=C sed...本地化并将输入视为二进制输入以避免解码问题(如果担心速度,可能会加快速度)

答案2

bash 5.1 带有可加载的 CSV 模块

BASH_LOADABLES_PATH=${BASH/\/bin\//\/lib\/}
enable -f csv csv
csv -a fields "$line"
new_line=$(IFS=$'\t'; echo "${fields[*]}")
declare -p line fields new_line

输出

declare -- line="a,\"test, part2 \"\"the start\"\"\",b"
declare -a fields=([0]="a" [1]="test, part2 \"the start\"" [2]="b")
declare -- new_line="a  test, part2 \"the start\"   b"
#.....................^ tab......................^ tab

如果有一个包含选项卡的字段,则这是无效的。


在管道中:

IFS=$'\t'
cat file |
while IFS= read -r line; do
    csv -a fields "$line"
    echo "${fields[*]}"
done |
tail

虽然这是更惯用的 bash

IFS=$'\t'
while IFS= read -r line; do
    csv -a fields "$line"
    echo "${fields[*]}"
done < file | tail

答案3

或者使用csvformat来自csvkit-- 该工具负责引用包含分隔符的任何字段:我在输入文件中添加了一行,其中包含制表符。

$ cat a.txt
a,"test, part2 ""the start""",b
c,d,e   with    tabs

$ csvformat -D $'\t' a.txt
a   "test, part2 ""the start""" b
c   d   "e  with    tabs"

相关内容