ネストされた参照を持つ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

ロード可能なCSVモジュールを含むbash 5.1

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"

関連情報