Saya perlu memuat dan menggunakan data file CSV di C ++. Pada titik ini, ia hanya bisa menjadi parser yang dipisah koma (mis. Jangan khawatir akan keluar dari baris dan koma baru). Kebutuhan utama adalah pengurai baris demi baris yang akan mengembalikan vektor untuk baris berikutnya setiap kali metode dipanggil.
Saya menemukan artikel ini yang terlihat cukup menjanjikan: http://www.boost.org/doc/libs/1_35_0/libs/spirit/example/fundamental/list_parser.cpp
Saya tidak pernah menggunakan Boost's Spirit, tetapi saya bersedia mencobanya. Tetapi hanya jika tidak ada solusi yang lebih mudah saya hadapi.
boost::spirit
parsing. Ini lebih untuk parsing tata bahasa, terima parsing format file sederhana. Seseorang di tim saya mencoba menggunakannya untuk mem-parsing XML dan itu menyusahkan untuk debug. Jauhiboost::spirit
jika memungkinkan.spirit
cukup sulit digunakan untuk pustaka kombinator perpustakaan. Setelah memiliki beberapa pengalaman (sangat menyenangkan) dengan(atto)parsec
perpustakaan Haskells saya berharap (semangat) untuk bekerja dengan baik, tetapi menyerah setelah berjuang dengan 600 baris kompiler kesalahan.Jawaban:
Jika Anda tidak peduli tentang keluar dari koma dan baris baru,
DAN Anda tidak dapat menanamkan koma dan baris baru dalam tanda kutip (Jika Anda tidak dapat melarikan diri maka ...)
maka hanya sekitar tiga baris kode (OK 14 -> Tapi itu hanya 15 untuk membaca seluruh file).
Saya hanya akan membuat kelas yang mewakili satu baris.
Kemudian streaming ke objek itu:
Tetapi dengan sedikit kerja kita secara teknis bisa membuat iterator:
sumber
istream::operator>>
(seperti Eigen), tambahkaninline
sebelum deklarasi operator untuk memperbaikinya.Solusi menggunakan Boost Tokenizer:
sumber
Versi saya tidak menggunakan apa pun kecuali pustaka C ++ 11 standar. Ini cocok dengan kutipan Excel CSV:
Kode ini ditulis sebagai mesin negara-terbatas dan mengkonsumsi satu karakter pada suatu waktu. Saya pikir itu lebih mudah untuk dipikirkan.
sumber
const char *vinit[] = {""}; vector<string> fields(vinit, end(vinit));
The C ++ String Toolkit Perpustakaan (StrTk) memiliki kelas jaringan token yang memungkinkan Anda untuk memuat data baik dari file teks, string atau buffer arang , dan untuk mengurai / proses mereka dengan cara baris-kolom.
Anda dapat menentukan pembatas baris dan pembatas kolom atau cukup gunakan default.
Lebih banyak contoh dapat ditemukan di sini
sumber
options.trim_dquotes = true
menghapus tanda kutip di sekitarnya (via ), strtk tidak mendukung penghapusan kutip ganda digandakan (misalnya bidang"She said ""oh no"", and left."
sebagai c-string"She said \"oh no\", and left."
). Anda harus melakukannya sendiri.strtk
, Anda juga harus menangani secara manual bidang yang dikutip ganda yang berisi karakter baris baru.Anda dapat menggunakan Boost Tokenizer dengan escaped_list_separator.
Ini hanya menggunakan file header tokenizer Boost, tidak perlu menautkan untuk meningkatkan perpustakaan.
Berikut ini sebuah contoh, (lihat Parse CSV File With Boost Tokenizer Di C ++ untuk detailnya atau
Boost::tokenizer
):sumber
Tidaklah berlebihan untuk menggunakan Spirit untuk mem-parsing CSV. Spirit cocok untuk tugas penguraian mikro. Misalnya, dengan Spirit 2.1, semudah:
Vektor, v, diisi dengan nilai-nilai. Ada serangkaian tutorial yang menyentuh ini di Spirit 2.1 docs baru yang baru saja dirilis dengan Boost 1.41.
Tutorial berkembang dari yang sederhana ke yang kompleks. Parser CSV disajikan di suatu tempat di tengah dan menyentuh berbagai teknik dalam menggunakan Spirit. Kode yang dihasilkan seketat kode tulisan tangan. Lihat assembler yang dihasilkan!
sumber
Jika Anda DO peduli tentang parsing CSV dengan benar, ini akan melakukannya ... relatif lambat karena bekerja satu char pada suatu waktu.
sumber
Saat menggunakan Boost Tokenizer escaped_list_separator untuk file CSV, maka orang harus mengetahui hal berikut:
Format CSV yang ditentukan oleh wiki menyatakan bahwa bidang data dapat berisi pemisah dalam tanda kutip (didukung):
Format CSV yang ditentukan oleh wiki menyatakan bahwa tanda kutip tunggal harus ditangani dengan tanda kutip ganda (escaped_list_separator akan menghapus semua karakter kutipan):
Format CSV tidak menentukan bahwa karakter back-slash apa pun harus dihapus (escaped_list_separator akan menghapus semua karakter escape).
Kemungkinan solusi untuk memperbaiki perilaku default dari boost escaped_list_separator:
Work-around ini memiliki efek samping yang mengosongkan bidang data yang diwakili oleh kuotasi ganda, akan ditransformasikan menjadi token kuotasi tunggal. Ketika melakukan iterasi melalui token, maka seseorang harus memeriksa apakah token itu merupakan tanda kutip tunggal, dan memperlakukannya seperti string kosong.
Tidak cantik tetapi berfungsi, selama tidak ada baris baru di dalam tanda kutip.
sumber
Anda mungkin ingin melihat CSVfix proyek FOSS saya ( tautan yang diperbarui ), yang merupakan editor aliran CSV yang ditulis dalam C ++. Pengurai CSV bukanlah hadiah, tetapi melakukan pekerjaan dan seluruh paket dapat melakukan apa yang Anda butuhkan tanpa Anda menulis kode apa pun.
Lihat alib / src / a_csv.cpp untuk parser CSV, dan csvlib / src / csved_ioman.cpp (
IOManager::ReadCSV
) untuk contoh penggunaan.sumber
Karena semua pertanyaan CSV sepertinya dialihkan ke sini, saya pikir saya akan memposting jawaban saya di sini. Jawaban ini tidak secara langsung menjawab pertanyaan si penanya. Saya ingin dapat membaca dalam aliran yang dikenal dalam format CSV, dan juga jenis masing-masing bidang sudah diketahui. Tentu saja, metode di bawah ini dapat digunakan untuk memperlakukan setiap bidang menjadi tipe string.
Sebagai contoh bagaimana saya ingin dapat menggunakan aliran input CSV, pertimbangkan input berikut (diambil dari halaman wikipedia di CSV ):
Kemudian, saya ingin dapat membaca data seperti ini:
Ini adalah solusi yang akhirnya saya dapatkan.
Dengan bantuan berikut yang dapat disederhanakan oleh templat ciri integral baru di C ++ 11:
Cobalah online!
sumber
Saya menulis parser CSV header-only, C ++ 11 . Telah diuji dengan baik, cepat, mendukung seluruh spesifikasi CSV (bidang yang dikutip, pembatas / terminator dalam tanda kutip, pelolosan kutipan, dll.), Dan dapat dikonfigurasi untuk memperhitungkan CSV yang tidak mematuhi spesifikasi.
Konfigurasi dilakukan melalui antarmuka yang lancar:
Parsing hanya rentang berdasarkan untuk loop:
sumber
Pustaka I / O CSV lain dapat ditemukan di sini:
http://code.google.com/p/fast-cpp-csv-parser/
sumber
Solusi lain yang mirip dengan jawaban Loki Astari , di C ++ 11. Baris di sini adalah
std::tuple
dari tipe yang diberikan. Kode memindai satu baris, kemudian memindai hingga setiap pembatas, dan kemudian mengkonversi dan membuang nilai langsung ke tuple (dengan sedikit kode templat).Penganjur:
std::tuple<t1, ...>
viaoperator>>
.Apa yang hilang:
Kode utama:
Saya memberikan contoh kerja yang kecil di GitHub ; Saya telah menggunakannya untuk mem-parsing beberapa data numerik dan melayani tujuannya.
sumber
Berikut ini adalah implementasi lain dari parser Unicode CSV (berfungsi dengan wchar_t). Saya menulis sebagian darinya, sementara Jonathan Leffler menulis sisanya.
Catatan: Parser ini bertujuan mereplikasi perilaku Excel sedekat mungkin, khususnya saat mengimpor file CSV yang rusak atau salah .
Ini adalah pertanyaan asli - Parsing file CSV dengan bidang multiline dan lolos dari tanda kutip ganda
Ini adalah kode sebagai SSCCE (Short, Self-Contained, Correct Example).
sumber
Saya membutuhkan pustaka C ++ yang mudah digunakan untuk mem-parsing file CSV tetapi tidak dapat menemukan yang tersedia, jadi saya akhirnya membangun satu. Rapidcsv adalah pustaka hanya header C ++ 11 yang memberikan akses langsung ke kolom yang diurai (atau baris) sebagai vektor, dalam tipe data pilihan. Sebagai contoh:
sumber
Maaf, tapi ini semua sepertinya banyak sintaksis yang rumit untuk menyembunyikan beberapa baris kode.
Kenapa tidak ini:
sumber
",\n"
string?Berikut ini adalah kode untuk membaca matriks, perhatikan Anda juga memiliki fungsi csvwrite di matlab
sumber
Anda dapat membuka dan membaca file .csv menggunakan fopen, fungsi fscanf, tetapi yang penting adalah mem-parsing data. Cara termudah untuk mem-parsing data menggunakan pembatas. Dalam kasus .csv, pembatas adalah ','.
Misalkan file data1.csv Anda adalah sebagai berikut:
Anda dapat mengidentifikasi data dan menyimpannya dalam array char dan kemudian menggunakan fungsi atoi () dll untuk konversi yang sesuai
[^,], ^ -itu membalikkan logika, berarti cocok dengan string apa pun yang tidak mengandung koma lalu terakhir, mengatakan untuk mencocokkan koma yang mengakhiri string sebelumnya.
sumber
Hal pertama yang perlu Anda lakukan adalah memastikan file itu ada. Untuk mencapai ini, Anda hanya perlu mencoba dan membuka aliran file di jalur. Setelah Anda membuka aliran file gunakan stream.fail () untuk melihat apakah itu berfungsi seperti yang diharapkan, atau tidak.
Anda juga harus memverifikasi bahwa file yang disediakan adalah jenis file yang benar. Untuk mencapai ini, Anda perlu melihat jalur file yang disediakan sampai Anda menemukan ekstensi file. Setelah Anda memiliki ekstensi file pastikan itu file .csv.
Fungsi ini akan mengembalikan ekstensi file yang digunakan kemudian dalam pesan kesalahan.
Fungsi ini sebenarnya akan memanggil pemeriksaan kesalahan yang dibuat di atas dan kemudian mem-parsing melalui file.
sumber
Anda harus merasa bangga ketika Anda menggunakan sesuatu yang sangat indah
boost::spirit
Di sini upaya saya untuk parser (hampir) mematuhi spesifikasi CSV pada tautan ini. Spesifikasi CSV (saya tidak perlu jeda baris di dalam bidang. Juga ruang di sekitar koma diberhentikan).
Setelah Anda mengatasi pengalaman mengejutkan dari menunggu 10 detik untuk menyusun kode ini :), Anda dapat duduk dan menikmati.
Menyusun:
Tes (contoh dicuri dari Wikipedia ):
sumber
Solusi ini mendeteksi 4 kasus ini
kelas lengkap ada di
https://github.com/pedro-vicente/csv-parser
Itu membaca karakter file dengan karakter, dan membaca 1 baris sekaligus ke vektor (string), oleh karena itu cocok untuk file yang sangat besar.
Penggunaan adalah
Iterasi sampai baris kosong dikembalikan (akhir file). Baris adalah vektor di mana setiap entri adalah kolom CSV.
deklarasi kelas
pelaksanaan
sumber
Anda juga bisa melihat kapabilitas
Qt
perpustakaan.Ini memiliki dukungan ekspresi reguler dan kelas QString memiliki metode yang bagus, misalnya
split()
mengembalikan QStringList, daftar string yang diperoleh dengan memisahkan string asli dengan pembatas yang disediakan. Harus mencukupi untuk file csv ..Untuk mendapatkan kolom dengan nama header yang diberikan, saya menggunakan yang berikut ini: c ++ inheritance Qt problem qstring
sumber
Jika Anda tidak ingin berurusan dengan memasukkan peningkatan dalam proyek Anda (itu sangat besar jika semua yang akan Anda gunakan adalah penguraian CSV ...)
Saya beruntung dengan penguraian CSV di sini:
http://www.zedwood.com/article/112/cpp-csv-parser
Ini menangani kolom yang dikutip - tetapi tidak menangani karakter sebaris \ n (yang mungkin bagus untuk sebagian besar penggunaan).
sumber
Ini adalah utas lama tetapi masih di bagian atas hasil pencarian, jadi saya menambahkan solusi saya menggunakan std :: stringstream dan metode penggantian string sederhana oleh Yves Baumes yang saya temukan di sini.
Contoh berikut akan membaca file baris demi baris, abaikan baris komentar yang dimulai dengan // dan parsing baris lainnya ke dalam kombinasi string, int, dan ganda. Stringstream melakukan parsing, tetapi mengharapkan bidang dibatasi oleh spasi, jadi saya menggunakan stringreplace untuk mengubah koma menjadi spasi terlebih dahulu. Ini menangani tab ok, tetapi tidak berurusan dengan string yang dikutip.
Masukan yang salah atau hilang diabaikan begitu saja, yang mungkin atau mungkin tidak baik, tergantung pada keadaan Anda.
sumber
Untuk apa nilainya, inilah implementasi saya. Ini berkaitan dengan input wstring, tetapi dapat disesuaikan dengan string dengan mudah. Ini tidak menangani baris baru di bidang (karena aplikasi saya juga tidak, tetapi menambahkan dukungannya tidak terlalu sulit) dan tidak mematuhi "\ r \ n" akhir baris sesuai RFC (dengan asumsi Anda menggunakan std :: getline), tetapi tidak menangani pemotongan spasi putih dan tanda kutip ganda dengan benar (mudah-mudahan).
sumber
Berikut adalah fungsi siap pakai jika yang Anda butuhkan adalah memuat file data ganda (tanpa bilangan bulat, tanpa teks).
sumber
Cara cepat dan mudah lainnya adalah dengan menggunakan
Boost.Fusion I/O
:Keluaran:
sumber
Saya menulis cara yang bagus untuk mem-parsing file CSV dan saya pikir saya harus menambahkannya sebagai jawaban:
sumber
Dimungkinkan untuk digunakan
std::regex
.Bergantung pada ukuran file Anda dan memori yang tersedia untuk Anda, dimungkinkan membacanya baik baris demi baris atau seluruhnya dalam
std::string
.Untuk membaca file, seseorang dapat menggunakan:
maka Anda dapat mencocokkan dengan ini yang sebenarnya disesuaikan dengan kebutuhan Anda.
sumber
Karena saya tidak terbiasa meningkatkan sekarang, saya akan menyarankan solusi yang lebih sederhana. Mari kita anggap bahwa file .csv Anda memiliki 100 baris dengan 10 angka di setiap baris yang dipisahkan oleh ','. Anda bisa memuat data ini dalam bentuk array dengan kode berikut:
sumber