중첩된 참조가 있는 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

여기에 문제가 있습니다: 누락 ,, 추가 탭, 추가 따옴표.

참고로 파이썬 코드의 형식도 잘못되었습니다.

[ 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"

관련 정보