CSV'yi TSV'ye Dönüştürme


27

Çok sayıda büyük CSV dosyam var ve bunların TSV'de olmasını istiyorum (sekmeyle ayrılmış biçim). Buradaki komplikasyon, CSV dosyasının alanlarında virgüllerin olmasıdır, örneğin:

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

Beklenen çıktı:

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

(aralarındaki boşluk 'sert' sekmelerdir)

Bu sunucuda yüklü Perl, Python ve coreutils var.


Bunu node.js veya perl ile yapardım.
peterh Monica

1
Alıntılanmayan virgülleri sekmelerle değiştirin ...
cricket_007

Evet, bu soruya 5 dakikadan fazla zaman kaldıysam. Ancak cevapları verdiğim oylarla memnuniyetle destekleyeceğim. Söylemeye çalıştığım, ortak sed / awk şeylerinin bunun için muhtemelen uygun olmadığı (en azından yaygın olarak kullanılan kullanımlarında).
peterh Monica

6
Örneğinizin gerçek verileri temsil edip etmediğinden emin değilim, ancak bunlar gerçek metin dizeleri olacaksa, dizginin bir sekme içerdiği durumu ele almanız gerekebileceğini unutmayın ...
AC

3
Diğer zor olan kısım, CSV'nin çok gevşek bir şekilde tanımlanmış bir format olması, gerçek bir standart olmamasıdır (bir RFC vardır ancak bundan yıllar sonra yazılmıştır). Bir dille sağlanan CSV ayrıştırıcısını kullanan bir kod yazdım ve daha sonra özel bir ayrıştırıcı ile yeniden yazmak zorunda kaldım, çünkü girdi verilerinin csv biçiminin bozuk bir değişkeninde olduğunu buldum.
plugwash

Yanıtlar:


37

piton

Adlı dosyaya ekle csv2tab.shve çalıştırılabilir yap

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

Test çalıştırması

$ 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
Olası bir hata: Bu cevap iç sekmelerden kaçmaz.
Morgen

4
@Morgen csv.writer(sys.stdout, dialect='excel-tab').writerows(csv.reader(sys.stdin))? Ayrıca döngü ortadan kaldırır.
muru

1
@chx dene python -c 'import csv,sys; csv.writer(sys.stdout, dialect="excel-tab").writerows(csv.reader(sys.stdin))'. -mBu şekilde çalıştığından şüpheliyim .
muru

18

Eğlenmek için sed.

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

Sizin seddesteklemiyorsa -E, deneyin -r. Eğer senin seddesteklemediği \tbir hazır sekmesi için, bir hazır sekmeyi koymayı deneyin (birçok kabuklarda, ctrl- v tab) ya da Bash, bir kullanma $'...'(içinde ters eğik çizgi bu durumda C tarzı dizesi \2ihtiyaçlarına katına edilecektir). Alıntıları saklamak istiyorsanız, \1bunun yerine kullanın \2(bu durumda iç parantez çifti kullanılamaz ve kaldırılabilir).

Bu, çift tırnak işareti içinde kaçış çift tırnak işareti kullanmaya kalkışmaz; Bazı CSV lehçleri, alıntı yapılan çift alıntıyı (sic) ikiye katlayarak bunu desteklemektedir.


1
Sanırım bunu başarmak için 100 farklı senaryo denedim ama tüm girişimlerim başarısız oldu. Bu harika.
George Vasiliou


13

Bir seçenek perl'in Text :: CSV modülü olabilir; örn.

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

göstermek

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
Bir alan bir sekme içeriyorsa doğru olmaz mıydı
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
}'

Sonuç:

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

+1 Perl versiyonu cazibeye benziyor
ATorras

4

Termonükleer sineklik çözeltisi libreoffice kullanıyor olmalı. iken https://ask.libreoffice.org/en/question/19042/is-is-possible-to-convert-comma-separated-value-csv-to-tab-separated-value-tsv-via-headless-mode / bunun mümkün olmadığını, ancak yanlış olduğunu (ya da sadece eski moda mı kaldığını gösterir) önerir ve aşağıdaki komut 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

envargüman Atlanan olabilir ama bu şekilde belgeler son belgede görünmez.


2
Bence gerçek termonükleer dalgakıran, LibreOffice'in UNO API'sı :) ile yapmak için bir Java programı yazacaktı.
Pont

3

csvtoolYardımcı programınız varsa veya kurabilirseniz :

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

Bazı nedenlerden dolayı csvtoolbir kılavuz sayfasına sahip olmadığına, ancak csvtool --helpbirkaç yüz satır belge yazdırılacağına dikkat edin.


3

Kullanımı mlrneredeyse kesin, ancak başlıkları devre dışı bırakmak uzun seçenekler gerektirir:

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

Çıktı:

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

3

Açıklamalı bir CSV - TSV dönüştürücüyü, açıklanan dönüşümleri idare eden bir araç olarak yazdım. Oldukça hızlı, büyük CSV dosyalarını dönüştürmeye devam eden bir ihtiyaç varsa, bakmaya değer olabilir. Araç, eBay'in TSV yardımcı programları araç setinin bir parçasıdır ( burada csv2tsv belgeleri ). Tanımlanan giriş için varsayılan seçenekler yeterlidir:

$ csv2tsv file.csv > file.tsv

2

gayret

Sadece eğlence için, düzenli ifade değiştirmelerin de yapılabilir Vim . İşte uyarlanan potansiyel bir dört satırlı çözüm: https://stackoverflow.com/questions/33332871/remove-all-commas-between-quotes-with-a-vim-regex

  1. Tırnaklar arasındaki virgüller ilk önce alt çizgi (veya başka bir eksik karakter) olarak değiştirilir,
  2. Diğer tüm virgüller sekmelerle değiştirilir,
  3. Tırnak içindeki alt çizgiler virgüllere döndürülür,
  4. Tırnak işaretleri kaldırıldı.

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

Çözümü biraz kodlamak için yukarıdaki dört satır (önde gelen iki nokta üst üste) bir dosyaya kaydedilebilir, örn to_tsv.vim. İle düzenleme için her bir CSV aç um ve ilgili komut um (uyarlanmıştır komut hattı https://stackoverflow.com/questions/3374179/run-vim-script-from-vim-commandline/8806874#8806874 ): sourceto_tsv.vim

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

1

jqYardımcı programı kullanarak CSV'yi TSV'ye dönüştürme örneği :

$ 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

veya:

$ 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

Ancak, CSV formatının iyi biçimlendirilmesi gerekir, bu yüzden her dize alıntı yapılması gerekir.

Kaynak: Basit TSV çıktı formatı .


1

Bununla birlikte perl, csv alanlarının gömülü "veya yeni satırları veya sekmeleri olmadığını varsayarak :

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

0

Aşağıdaki, @ tripleee'den gelen cevabın bir düzeltmesidir, böylece final alanındaki herhangi bir alıntıyı diğer tüm alanlarda olduğu gibi çıkarır .

Neyin düzeltildiğini göstermek için, aşağıda üçlü bir kişinin cevabı ve son olarak ' Z ' alanı çevresinde alıntılar eklenmiş olan OP'nin örnek verilerinde küçük bir değişiklik yapıldı .

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 ' nin etrafına tırnak işaretleri kaldığını görebilirsiniz . Bu, iç alanların nasıl işlendiğinden farklıdır. Örneğin, ' G ' üzerinde tırnak yoktur.

Aşağıdaki komut, son sütunu temizlemek için ikinci bir değiştirme kullanır:

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
Giriş verileri 'A,,C,"D,E,F","G",I,"K,L,M","Z,A"'bu cevaba girildiğinde , doğru değil "Z,A", yanlış olarak değiştirilir . Z AZ,A
agc
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.