CSV를 TSV로 변환


27

대용량 CSV 파일이 많이 있으며 TSV (탭으로 구분 된 형식) 형식으로 원합니다. 합병증은 CSV 파일의 필드에 쉼표가 있다는 것입니다. 예를 들면 다음과 같습니다.

 A,,C,"D,E,F","G",I,"K,L,M",Z

예상 출력 :

 A      C   D,E,F   G   I   K,L,M   Z

(사이의 공백은 '하드'탭입니다)

이 서버에 Perl, Python 및 coreutils가 설치되어 있습니다.


node.js 또는 perl을 사용 하여이 작업을 수행합니다.
peterh는 모니카 복원

1
... 탭 비 인용 쉼표를 교체
cricket_007

예,이 질문에 5 분 이상 걸린다면 그러나 나는 투표로 응답자들을 행복하게 지원할 것입니다. 내가 말하려고 한 것은 일반적인 sed / awk 것들이 (적어도 일반적으로 사용되는 사용법으로는) 적합하지 않다는 것입니다.
peterh는 모니카 복원

6
예제가 실제 데이터를 나타내는 지 확실하지 않지만 실제 텍스트 문자열이 될 경우 문자열에 탭이 포함 된 경우를 처리해야 할 수도 있습니다.
AC

3
또 다른 까다로운 부분은 CSV가 매우 느슨하게 정의 된 형식이며 실제 표준은 없지만 RFC는 있지만 실제로 몇 년 후에 작성된 것입니다. 언어 제공 CSV 파서를 사용하는 코드를 작성한 다음 입력 데이터가 csv 형식의 변형 된 형식이라는 것을 알았으므로 사용자 정의 파서로 다시 작성해야했습니다.
plugwash

답변:


37

파이썬

라는 파일에 추가 csv2tab.sh하고 실행 가능하게 만드십시오.

#!/usr/bin/env python
import csv, sys
csv.writer(sys.stdout, dialect='excel-tab').writerows(csv.reader(sys.stdin))

시운전

$ echo 'A,,C,"D,E,F","G",I,"K,L,M",Z' | ./csv2tab.sh                         
A       C   D,E,F   G   I   K,L,M   Z

$ ./csv2tab.sh < data.csv > data.tsv && head data.tsv                                                   
1A      C   D,E,F   G   I   K,L,M   Z
2A      C   D,E,F   G   I   K,L,M   Z
3A      C   D,E,F   G   I   K,L,M   Z

5
가능한 버그 :이 답변은 내부 탭을 이스케이프하지 않습니다.
Morgen

4
@ 모르 겐 csv.writer(sys.stdout, dialect='excel-tab').writerows(csv.reader(sys.stdin))? 루프도 제거합니다.
muru

1
@chx 시도하십시오 python -c 'import csv,sys; csv.writer(sys.stdout, dialect="excel-tab").writerows(csv.reader(sys.stdin))'. 나는 -m그런 식으로 작동합니다.
muru

18

재미를 위해 sed.

sed -E 's/("([^"]*)")?,/\2\t/g' file

sed지원하지 않는 경우로 -E시도하십시오 -r. 리터럴 탭을 sed지원하지 않는 경우 \t리터럴 탭 (많은 쉘, ctrl- v tab) 또는 Bash에 $'...'C 스타일 문자열을 사용하십시오 (이 경우 백 슬래시를 \2두 배로 늘려야 함). 따옴표를 유지하려면 \1대신 사용하십시오 \2(이 경우 괄호의 내부 쌍은 쓸모 없으며 제거 할 수 있음).

이것은 큰 따옴표 안의 이스케이프 된 큰 따옴표를 처리하려고 시도하지 않습니다. 일부 CSV 방언은 인용 된 큰 따옴표 (sic)를 두 배로하여이를 지원합니다.


1
나는 이것을 달성하기 위해 약 100 개의 다른 sed 스크립트를 시도했지만 내 시도는 모두 실패했다고 생각합니다. 대단해.
George Vasiliou

16

csvkit유틸리티 (Python) 사용 예 :

$ csvformat -T in.csv > out.txt

올바른 CSV 및 TSV 인용 및 이스케이프를 사용하여 스트리밍

apt 및 기타 패키지 관리자에 있습니다.


13

하나의 옵션은 펄의 Text :: CSV 모듈입니다.

perl -MText::CSV -lne 'BEGIN { $csv = Text::CSV->new() }
  print join "\t", $csv->fields() if $csv->parse($_)
' somefile

설명하기 위해

echo 'A,,C,"D,E,F","G",I,"K,L,M",Z' |
  perl -MText::CSV -lne 'BEGIN { $csv = Text::CSV->new() }
  print join "\t", $csv->fields() if $csv->parse($_)
'
A       C   D,E,F   G   I   K,L,M   Z

1
필드에 탭이 포함 된 경우 올바르지 않습니다
Neil McGuigan

6

perl -lne '
   my $re = qr/,(?=(?:[^"]*"[^"]*")*(?![^"]*"))/;
   print join "\t", map { s/(?<!\\)"//gr =~ s/\\"/"/gr } split $re;
'

어 wk

awk -v Q=\" -v FPAT="([^,]*)|(\"[^\"]+\")" -v OFS="\t" '{
   for (i=1; i<=NF; ++i)
      if ( substr($i, 1, 1) == Q )
         $i = substr($i, 2, length($i) - 2)
   print $1, $2, $3, $4, $5, $6, $7, $8
}'

결과:

A               C       D,E,F   G       I       K,L,M   Z

+1 Perl 버전은 매력처럼 작동합니다
ATorras

4

열핵 플라이스와 터 솔루션은 libreoffice를 사용해야합니다. https://ask.libreoffice.org/en/question/19042/is-is-possible-to-convert-comma-separated-value-csv-to-tab-separated-value-tsv-via-headless-mode 동안 / 이것이 가능하지는 않지만 잘못되었거나 오래 되었습니까? 다음 명령은 5.3에서 작동합니다.

loffice "-env:UserInstallation=file:///tmp/LibO_Conversion" --convert-to csv:"Text - txt - csv (StarCalc)":9,34,UTF8 --headless --outdir some/path --infilter='csv:44,34,UTF8' *.csv

env인수는 생략 될 수 있지만,이 방법은 문서를 최근 문서에 표시되지 않습니다.


2
진정한 열핵 플라이와 터는 LibreOffice의 UNO API를 통해 Java 유틸리티를 작성한다고 생각합니다. :)
Pont

3

csvtool유틸리티가 있거나 설치할 수있는 경우 :

csvtool -t COMMA -u TAB cat in.csv > out.ctv

어떤 이유로 csvtool매뉴얼 페이지가 없지만 csvtool --help수백 줄의 문서를 인쇄합니다.


3

사용 mlr은 거의 간결하지만 헤더를 비활성화하려면 긴 옵션이 필요합니다.

mlr --c2t --implicit-csv-header --headerless-csv-output cat file.csv 

산출:

A       C   D,E,F   G   I   K,L,M   Z

3

설명 된 변환을 처리하는 오픈 소스 CSV-TSV 변환기를 작성했습니다. 대용량 CSV 파일을 계속 변환 해야하는 경우 상당히 빠릅니다. 툴은 eBay의 TSV 유틸리티 툴킷 (csv2tsv documentation here ) 일부입니다 . 설명 된 입력에 대해서는 기본 옵션으로 충분합니다.

$ csv2tsv file.csv > file.tsv

2

정력

재미를 위해 정규 표현식 대체는 Vim 에서 수행 할 수 있습니다 . https : //.com/questions/33332871/remove-all-comma-between-quotes-with-a-vim-regex

  1. 따옴표 사이의 쉼표는 먼저 밑줄 (또는 다른 부재 문자)로 변경됩니다.
  2. 다른 모든 쉼표는 탭으로 바뀌고
  3. 따옴표 안의 밑줄은 쉼표로 복원됩니다.
  4. 따옴표가 제거됩니다.

    :%s/".\{-}"/\=substitute(submatch(0), ',', '_' , 'g')/g
    :%s/,/\t/g
    :%s/_/,/g
    :%s/"//g

솔루션을 다소 스크립팅하기 위해 위의 네 줄 (산행 콜론)을 파일에 저장할 수 있습니다 (예 :) to_tsv.vim. VimVim 명령 줄 sourceto_tsv.vim스크립트 ( https://stackoverflow.com/questions/3374179/run-vim-script-from-vim-commandline/8806874#8806874 에서 수정)를 사용하여 편집 할 각 CSV를 엽니 다 .

    :source /path/to/vim/filename/to_tsv.vim

1

다음은 jq유틸리티를 사용하여 CSV를 TSV로 변환하는 예입니다 .

$ jq -rn '@tsv "\(["A","","C","D,E,F","G","I","K,L,M","Z"])"'
A       C   D,E,F   G   I   K,L,M   Z

또는:

$ echo '["A","","C","D,E,F","G","I","K,L,M","Z"]' | jq -r @tsv
A       C   D,E,F   G   I   K,L,M   Z

그러나 CSV 형식의 형식이 적절해야하므로 각 문자열을 인용해야합니다.

출처 : 간단한 TSV 출력 형식 .


1

perlcsv 필드에 포함 된 줄 "바꿈이나 탭 이 없다고 가정 합니다.

perl -pe 's{"(.*?)"|,}{$1//"\t"}ge'

0

다음은 @tripleee 의 답변을 간단히 수정 하여 다른 모든 필드와 마찬가지로 최종 필드의 따옴표를 제거합니다.

수정 된 내용을 보여주기 위해 다음은 3 인의 답변과 최종 ' Z '필드 주위에 따옴표가 추가 된 OP의 예제 데이터를 약간 수정 한 것 입니다.

echo 'A,,C,"D,E,F","G",I,"K,L,M","Z"' |  sed -r -e 's/("([^"]*)")?,/\2\t/g'
A       C   D,E,F   G   I   K,L,M   "Z"

' Z '주위에 따옴표가 붙어 있음을 알 수 있습니다. 이것은 내부 필드가 처리되는 방식과 다릅니다. 예를 들어, ' G '에는 따옴표가 없습니다.

다음 명령은 두 번째 대체를 사용하여 최종 열을 정리합니다.

echo 'A,,C,"D,E,F","G",I,"K,L,M","Z"' |  sed -r -e 's/("([^"]*)")?,/\2\t/g' \
                                                -e 's/\t"([^"]*)"$/\t\1/'
A       C   D,E,F   G   I   K,L,M   Z

1
입력 데이터 'A,,C,"D,E,F","G",I,"K,L,M","Z,A"'가이 답변에 입력 되면 올바른가 "Z,A"아닌가로 대체됩니다 . Z AZ,A
agc
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.