Chuyển đổi CSV sang TSV


27

Tôi có một số tệp CSV lớn và muốn chúng ở TSV (định dạng được phân tách bằng tab). Điều phức tạp là có các dấu phẩy trong các trường của tệp CSV, ví dụ:

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

Sản lượng dự kiến:

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

(trong đó khoảng trắng ở giữa là các tab 'cứng')

Tôi đã cài đặt Perl, Python và coreutils trên máy chủ này.


Tôi sẽ làm điều này với node.js hoặc với perl.
peterh nói phục hồi Monica

1
Thay thế dấu phẩy không được trích dẫn bằng các tab ...
cricket_007

Có, nếu tôi có hơn 5 phút cho câu hỏi này. Nhưng tôi sẽ vui vẻ ủng hộ những người trả lời bằng phiếu bầu của tôi. Những gì tôi đã cố gắng nói, rằng những thứ sed / awk thông thường có lẽ không đủ điều kiện cho điều đó (ít nhất là trong cách sử dụng thường được sử dụng của chúng).
peterh nói phục hồi Monica

6
Tôi không chắc liệu ví dụ của bạn có đại diện cho dữ liệu thực tế hay không, nhưng nếu đó là những chuỗi văn bản thực tế thì đừng quên rằng bạn có thể cần xử lý trường hợp chuỗi bao gồm một tab ...
AC

3
Phần khó khăn khác là CSV là một định dạng rất lỏng lẻo, không có tiêu chuẩn thực sự (có RFC nhưng nó đã được viết nhiều năm sau khi thực tế). Tôi đã viết mã sử dụng trình phân tích cú pháp CSV do ngôn ngữ cung cấp và sau đó phải viết lại bằng trình phân tích cú pháp tùy chỉnh vì tôi thấy dữ liệu đầu vào là một biến thể bị hỏng của định dạng csv.
cắm vào

Câu trả lời:


37

Con trăn

Thêm vào tệp có tên csv2tab.shvà thực hiện nó

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

Chạy thử

$ 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
Một lỗi có thể xảy ra: câu trả lời này không thoát khỏi các tab nội bộ.
Morgen

4
@Morgen csv.writer(sys.stdout, dialect='excel-tab').writerows(csv.reader(sys.stdin))? Loại bỏ các vòng lặp là tốt.
muru

1
@chx thử python -c 'import csv,sys; csv.writer(sys.stdout, dialect="excel-tab").writerows(csv.reader(sys.stdin))'. Tôi nghi ngờ -mlàm việc theo cách đó.
muru

18

Để giải trí , sed.

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

Nếu bạn sedkhông hỗ trợ -E, hãy thử với -r. Nếu bạn sedkhông hỗ trợ \ttab theo nghĩa đen, hãy thử đặt một tab bằng chữ (trong nhiều shell, ctrl- v tab) hoặc trong Bash, sử dụng $'...'chuỗi kiểu C (trong trường hợp dấu gạch chéo ngược \2cần phải được nhân đôi). Nếu bạn muốn giữ dấu ngoặc kép, hãy sử dụng \1thay vì \2(trong trường hợp đó, cặp dấu ngoặc trong là vô dụng và có thể được gỡ bỏ).

Điều này làm cho không có nỗ lực để xử lý thoát dấu ngoặc kép bên trong dấu ngoặc kép; một số phương ngữ CSV hỗ trợ điều này bằng cách nhân đôi trích dẫn kép được trích dẫn (sic).


1
Tôi nghĩ rằng tôi đã thử khoảng 100 kịch bản sed khác nhau để đạt được điều này nhưng tất cả các nỗ lực của tôi đều thất bại. Điều này thật tuyệt.
George Vasiliou

16

Sử dụng csvkittiện ích (Python), ví dụ:

$ csvformat -T in.csv > out.txt

Có phát trực tuyến không, với trích dẫn CSV và TSV chính xác và thoát

Đó là trong apt và các trình quản lý gói khác


13

Một tùy chọn có thể là mô-đun Text :: CSV của perl, vd

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

để lam sang tỏ

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
Sẽ không chính xác nếu một trường có chứa một tab
Neil McGuigan

6

Perl

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

Awk

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
}'

Kết quả:

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

Phiên bản +1 Perl hoạt động như một bùa mê
ATorras

4

Các giải pháp flyswatter nhiệt hạch phải được sử dụng libreoffice. Trong khi https://ask.libreoffice.org/en/question/19042/is-is-possible-to-convert-comma-separated-value-csv-to-tab-separated-value-tsv-via-headless-mode / cho thấy điều này là không thể nhưng nó sai (hoặc chỉ lỗi thời?) và lệnh sau hoạt động trên 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

các envtham số có thể bỏ qua nhưng cách này các tài liệu sẽ không xuất hiện trong tài liệu gần đây của bạn.


2
Tôi nghĩ rằng flyswatter nhiệt hạch thực sự sẽ viết một tiện ích Java để làm điều đó thông qua API UNO của LibreOffice :).
Pont

3

Nếu bạn có hoặc có thể cài đặt, csvtooltiện ích:

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

Lưu ý rằng vì một số lý do csvtoolkhông có trang nam, nhưng csvtool --helpsẽ in vài trăm dòng tài liệu.


3

Việc sử dụng mlrgần như ngắn gọn, nhưng việc vô hiệu hóa các tiêu đề đòi hỏi các tùy chọn dài:

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

Đầu ra:

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

3

Tôi đã tạo ra một trình chuyển đổi CSV sang TSV mã nguồn mở để xử lý các biến đổi được mô tả. Nó khá nhanh, có thể đáng xem nếu có nhu cầu liên tục chuyển đổi các tệp CSV lớn. Công cụ là một phần của bộ công cụ tiện ích TSV của eBay (tài liệu csv2tsv tại đây ). Tùy chọn mặc định đủ cho đầu vào được mô tả:

$ csv2tsv file.csv > file.tsv

2

Vim

Chỉ để cho vui, sự thay thế regex có thể được thực hiện trong Vim . Đây là một giải pháp bốn dòng tiềm năng, được điều chỉnh từ: https://stackoverflow.com/questions/33332871/remove-all-commas-b between-quotes-with-a-vim-regex

  1. Dấu phẩy giữa các dấu ngoặc kép được thay đổi đầu tiên thành dấu gạch dưới (hoặc ký tự vắng mặt khác),
  2. Tất cả các dấu phẩy khác được thay thế bằng các tab,
  3. Dấu gạch dưới bên trong dấu ngoặc kép được khôi phục thành dấu phẩy,
  4. Dấu ngoặc kép được loại bỏ.

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

Để kịch bản giải pháp phần nào, bốn dòng trên (sans dấu hai chấm) có thể được lưu vào một tệp, ví dụ to_tsv.vim. Mở mỗi CSV để chỉnh sửa với Vimsourcecác to_tsv.vimkịch bản trên Vim dòng lệnh (chuyển thể từ https://stackoverflow.com/questions/3374179/run-vim-script-from-vim-commandline/8806874#8806874 ):

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

1

Dưới đây là ví dụ về chuyển đổi CSV thành TSV bằng jqtiện ích :

$ 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

hoặc là:

$ 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

Tuy nhiên, định dạng CSV cần được định dạng tốt, vì vậy mỗi chuỗi cần được trích dẫn.

Nguồn: Định dạng đầu ra TSV đơn giản .


1

Với perl, giả sử các trường csv không có "tab hoặc dòng mới được nhúng hoặc mới:

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

0

Sau đây chỉ đơn giản là một sự điều chỉnh cho câu trả lời từ @tripleee để nó loại bỏ bất kỳ trích dẫn nào từ trường cuối cùng giống như tất cả các trường khác.

Để hiển thị những gì đang được sửa chữa, dưới đây là một tripleee 's câu trả lời, cộng với một sửa đổi nhỏ để dữ liệu ví dụ của OP với trích dẫn thêm xung quanh trận chung kết' Z trường '.

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"

Bạn có thể thấy rằng ' Z ' được để lại với các trích dẫn xung quanh nó. Điều này khác với cách các trường bên trong được xử lý. Ví dụ: ' G ' không có dấu ngoặc kép trên đó.

Lệnh sau sử dụng thay thế thứ hai để làm sạch cột cuối cùng:

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
Khi dữ liệu đầu vào 'A,,C,"D,E,F","G",I,"K,L,M","Z,A"'là đầu vào cho câu trả lời này, thì dữ liệu được "Z,A"thay thế không chính xác Z A, thay vì chính xác Z,A.
agc
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.