2010-03-29 32 views
36

Tôi có tệp phân tách bằng tab có hơn 200 triệu dòng. Cách nhanh nhất trong Linux để chuyển đổi tệp này thành tệp csv là gì? Tệp này có nhiều dòng thông tin tiêu đề mà tôi sẽ cần phải loại bỏ đường, nhưng số lượng dòng tiêu đề được biết. Tôi đã thấy các đề xuất cho sedgawk, nhưng tôi tự hỏi nếu có lựa chọn "ưa thích".cách nhanh nhất chuyển đổi tệp được phân cách bằng tab thành csv trong linux

Chỉ cần làm rõ, không có tab được nhúng nào trong tệp này.

+0

Đối với csv to tsv và các dấu phân tách được nhúng, xem thêm câu trả lời cho http://stackoverflow.com/questions/13475535/replace-every-comma-not-enclosed-in-a-pair-of-double -quotes-with (cũng có liên quan: http://unix.stackexchange.com/questions/48672/remove-comma-between-the-quotes-only-in-a-comma-delimited-file). –

Trả lời

38

Nếu tất cả những gì bạn cần làm là dịch tất cả các ký tự tab thành ký tự dấu phẩy, tr có thể là cách để thực hiện.

Không gian trống ở đây là một tab đen:

$ echo "hello world" | tr "\\t" "," 
hello,world 

Tất nhiên, nếu bạn đã nhúng các tab bên literals chuỗi trong file, điều này sẽ không đúng cách dịch những cũng; nhưng các tab theo ngữ cảnh được nhúng sẽ khá phổ biến.

+13

Phổ biến hơn là các dấu phẩy được nhúng trong nguồn, sau đó yêu cầu gói với dấu ngoặc kép. Đó là rắc rối nếu có dấu ngoặc nhúng ... – kibibu

+0

Cảm ơn gợi ý 'tr'. Làm thế nào để so sánh với 'sed' với tốc độ? Giả sử bạn muốn bỏ qua tiêu đề bắt đầu ở dòng số x và tiếp tục phần còn lại của tệp. Có cách nào để thực hiện điều này với 'tr'? (Tôi cũng nên làm rõ rằng không có dấu phẩy được nhúng trong tệp.) – andrewj

+0

@andrewj: 'tr' sẽ nhanh hơn nhiều, vì nó chỉ thay thế ký tự thay thế bằng ký tự regex. Đối với bỏ qua tiêu đề, điều dễ nhất là chỉ xử lý theo hai khối - nếu bạn biết độ dài, đầu vào 'đầu -n > đầu ra; tail -n + đầu vào | tr ... >> output'; nếu bạn không biết chiều dài, có lẽ một cái gì đó với 'grep -n' ... – Cascabel

62

Nếu bạn lo lắng về các dấu phẩy được nhúng thì bạn sẽ cần phải sử dụng một phương pháp thông minh hơn một chút. Dưới đây là một kịch bản Python mà sẽ đưa dòng TSV từ stdin và viết dòng CSV để stdout:

import sys 
import csv 

tabin = csv.reader(sys.stdin, dialect=csv.excel_tab) 
commaout = csv.writer(sys.stdout, dialect=csv.excel) 
for row in tabin: 
    commaout.writerow(row) 

Run nó từ một vỏ như sau:

python script.py <input.tsv> output.csv 
+1

Trừ khi bạn biết chắc chắn rằng không có dấu phẩy được nhúng và không có tab được nhúng, đây là một cách rất đáng tin cậy để thực hiện. Mặc dù nó có thể không đáp ứng các tiêu chí để trở thành 'nhanh nhất'. – leedm777

+2

Nó có thể không phải là "nhanh nhất", nhưng nó xử lý các tab nhúng và dấu phẩy cho tôi. – anshuman

+1

Đá này. Tôi đã viết một kịch bản sed khó hiểu để chăm sóc điều này trong bash - nhưng điều đó không thể cạnh tranh với tính đầy đủ của thư viện csv python. Cảm ơn bạn Ignacio, cho cung cấp này. Về tốc độ - Dễ sử dụng và tốc độ đường đi đáng tin cậy - điều này chắc chắn đủ nhanh. :-) – dlink

3

giả sử bạn không muốn thay đổi tiêu đề và giả định bạn không có các tab được nhúng

# cat file 
header header header 
one  two  three 

$ awk 'NR>1{$1=$1}1' OFS="," file 
header header header 
one,two,three 

NR> 1 bỏ qua tiêu đề đầu tiên. bạn đã đề cập đến bạn biết có bao nhiêu dòng tiêu đề, vì vậy hãy sử dụng số chính xác cho trường hợp của riêng bạn. với điều này, bạn cũng không cần phải gọi bất kỳ lệnh bên ngoài nào khác. chỉ một lệnh awk thực hiện công việc.

một cách khác nếu bạn có các cột trống và bạn quan tâm đến điều đó.

awk 'NR>1{gsub("\t",",")}1' file 

bằng cách sử dụng sed

sed '2,$y/\t/,/' file #skip 1 line header and translate (same as tr) 
6
sed -e 's/"/\\"/g' -e 's/<tab>/","/g' -e 's/^/"/' -e 's/$/"/' infile > outfile 

Chết tiệt các nhà phê bình, trích dẫn tất cả mọi thứ, CSV không quan tâm.

<tab> là ký tự tab thực tế. không làm việc cho tôi. Trong bash, sử dụng^V để nhập nó.

+0

tab, bạn có thể thực hiện 'sed -e 's /"/\\ "/ g' -e" s/\ t/\ ", \"/g "-e 's/^ /" /' -e 's/$/"/ 'infile> outfile'. –

15
perl -lpe 's/"/""/g; s/^|$/"/g; s/\t/","/g' <input.tab> output.csv 

Perl thường nhanh hơn ở loại điều này so với sed, awk và Python.

+1

câu trả lời hay nhất cho tôi, chỉ một chút thay đổi, scape dấu ngoặc kép: perl -lpe' s /"/\\ "/ g; s/^ | $ /"/g; s/\ t/","/g '<... – Lix

+0

dài sống Perl! Chính xác là một lớp lót mà tôi cần. – Debriter

+0

Bạn là vị cứu tinh – Yankee

0

các oneliner awk sau hỗ trợ trích dẫn + quote-thoát

printf "flop\tflap\"" | awk -F '\t' '{ gsub(/"/,"\"\"\"",$i); for(i = 1; i <= NF; i++) { printf "\"%s\"",$i; if(i < NF) printf "," }; printf "\n" }' 

cho

"flop","flap"""" 
4

@ giải pháp python ignacio-Vazquez-abrams 's là tuyệt vời! Đối với những người đang tìm cách phân tích cú pháp phân cách các tab khác, thư viện thực sự cho phép bạn đặt dấu phân cách tùy ý.Đây là phiên bản của tôi thay đổi để xử lý các file ống được phân định:

import sys 
import csv 

pipein = csv.reader(sys.stdin, delimiter='|') 
commaout = csv.writer(sys.stdout, dialect=csv.excel) 
for row in pipein: 
    commaout.writerow(row) 
4
  • Nếu bạn muốn chuyển đổi các tập tin toàn bộ tsv vào một tập tin csv:

    $ cat data.tsv | tr "\\t" "," > data.csv 
    

  • Nếu bạn muốn để bỏ qua một số trường:

    $ cat data.tsv | cut -f1,2,3 | tr "\\t" "," > data.csv 
    

    lệnh trên sẽ chuyển đổi tệp data.tsv thành tệp data.csv chỉ chứa ba trường đầu tiên.

+1

rất tốt :) –

Các vấn đề liên quan