আমি কীভাবে সি ++ এ সিএসভি ফাইলগুলি পড়তে এবং পার্স করতে পারি?


264

আমাকে সি ++ এ সিএসভি ফাইল ডেটা লোড এবং ব্যবহার করতে হবে। এই মুহুর্তে এটি সত্যিই কেবল কমা-বিস্মৃত পার্সার হতে পারে (যেমন নতুন লাইন এবং কমা থেকে মুক্তি পাওয়ার বিষয়ে চিন্তা করবেন না)। প্রধান প্রয়োজনটি হ'ল একটি লাইন বাই লাইন পার্সার যা প্রতিবার পদ্ধতিটি বলা হওয়ার পরে পরবর্তী লাইনের জন্য কোনও ভেক্টরকে ফিরিয়ে দেবে।

আমি এই নিবন্ধটি পেয়েছি যা বেশ প্রতিশ্রুতিবদ্ধ দেখাচ্ছে: http://www.boost.org/doc/libs/1_35_0/libs/spirit/example/fundament/list_parser.cpp

আমি কখনই বুস্টের স্পিরিট ব্যবহার করি নি, তবে চেষ্টা করতে রাজি আছি। তবে এর চেয়ে আরও সহজ সমাধান না হলে কেবল আমিই উপেক্ষা করছি।


11
আমি boost::spiritপার্সিং জন্য তাকিয়ে আছে । ব্যাকরণকে পার্স করার জন্য এটি একটি সাধারণ ফাইল ফর্ম্যাটকে পার্স করার জন্য ধন্যবাদ। আমার টিমের কেউ এটিকে XML পার্স করার জন্য ব্যবহার করার চেষ্টা করছিল এবং এটি ডিবাগ করার জন্য ব্যথা হয়েছিল। boost::spiritসম্ভব হলে দূরে থাকুন ।
ক্রিশ

50
দুঃখিত ক্রিশ, তবে এটি ভয়ানক পরামর্শ। স্পিরিট সর্বদা উপযুক্ত সমাধান নয় তবে আমি এটি ব্যবহার করেছি - এবং এটি বেশিরভাগ প্রকল্পে সাফল্যের সাথে ব্যবহার করে চালিয়ে যাচ্ছি। অনুরূপ সরঞ্জামগুলির সাথে তুলনা করে (অ্যান্টলার, লেক্স / ইয়্যাক ইত্যাদি) এর উল্লেখযোগ্য সুবিধা রয়েছে। এখন, সিএসভি পার্স করার জন্য সম্ভবত এটি ওভারকিল ...
ম্যাটিটি

4
@ ম্যাটিটি আইএমএইচও spiritপার্সার কম্বিনেটর লাইব্রেরির জন্য ব্যবহার করা বেশ শক্ত। হাস্কেলস (atto)parsecলাইব্রেরিগুলির সাথে কিছু (খুব মনোরম) অভিজ্ঞতা থাকার পরে আমি আশা করেছি যে এটি (স্পিরিট) একইভাবে ভালভাবে কাজ করবে, তবে line০০ লাইনের সংকলক ত্রুটির সাথে লড়াই করার পরে এটি ছেড়ে দিয়েছি।
ফো

1
সি CSV তে পার্সার: sourceforge.net/projects/cccsvparser সি CSV তে লেখক: sourceforge.net/projects/cccsvwriter
SomethingSomething

উত্তর:


296

যদি আপনি কমা এবং নিউলাইন পলায়নের বিষয়ে চিন্তা করেন না,
এবং আপনি কোমা এবং নিউলাইন এম্বেড করতে পারবেন না কোটায় (যদি আপনি তখন পালাতে না পারেন ...)
তবে এটি কোডের প্রায় তিনটি লাইন (ঠিক আছে 14 -> তবে এটি পুরো ফাইলটি পড়ার জন্য কেবল 15)।

std::vector<std::string> getNextLineAndSplitIntoTokens(std::istream& str)
{
    std::vector<std::string>   result;
    std::string                line;
    std::getline(str,line);

    std::stringstream          lineStream(line);
    std::string                cell;

    while(std::getline(lineStream,cell, ','))
    {
        result.push_back(cell);
    }
    // This checks for a trailing comma with no data after it.
    if (!lineStream && cell.empty())
    {
        // If there was a trailing comma then add an empty element.
        result.push_back("");
    }
    return result;
}

আমি কেবল একটি সারি উপস্থাপন করে একটি শ্রেণি তৈরি করব।
তারপরে সেই বস্তুতে প্রবাহিত করুন:

#include <iterator>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>

class CSVRow
{
    public:
        std::string const& operator[](std::size_t index) const
        {
            return m_data[index];
        }
        std::size_t size() const
        {
            return m_data.size();
        }
        void readNextRow(std::istream& str)
        {
            std::string         line;
            std::getline(str, line);

            std::stringstream   lineStream(line);
            std::string         cell;

            m_data.clear();
            while(std::getline(lineStream, cell, ','))
            {
                m_data.push_back(cell);
            }
            // This checks for a trailing comma with no data after it.
            if (!lineStream && cell.empty())
            {
                // If there was a trailing comma then add an empty element.
                m_data.push_back("");
            }
        }
    private:
        std::vector<std::string>    m_data;
};

std::istream& operator>>(std::istream& str, CSVRow& data)
{
    data.readNextRow(str);
    return str;
}   
int main()
{
    std::ifstream       file("plop.csv");

    CSVRow              row;
    while(file >> row)
    {
        std::cout << "4th Element(" << row[3] << ")\n";
    }
}

তবে সামান্য কাজ দিয়ে আমরা প্রযুক্তিগতভাবে একটি পুনরুক্তি তৈরি করতে পারতাম:

class CSVIterator
{   
    public:
        typedef std::input_iterator_tag     iterator_category;
        typedef CSVRow                      value_type;
        typedef std::size_t                 difference_type;
        typedef CSVRow*                     pointer;
        typedef CSVRow&                     reference;

        CSVIterator(std::istream& str)  :m_str(str.good()?&str:NULL) { ++(*this); }
        CSVIterator()                   :m_str(NULL) {}

        // Pre Increment
        CSVIterator& operator++()               {if (m_str) { if (!((*m_str) >> m_row)){m_str = NULL;}}return *this;}
        // Post increment
        CSVIterator operator++(int)             {CSVIterator    tmp(*this);++(*this);return tmp;}
        CSVRow const& operator*()   const       {return m_row;}
        CSVRow const* operator->()  const       {return &m_row;}

        bool operator==(CSVIterator const& rhs) {return ((this == &rhs) || ((this->m_str == NULL) && (rhs.m_str == NULL)));}
        bool operator!=(CSVIterator const& rhs) {return !((*this) == rhs);}
    private:
        std::istream*       m_str;
        CSVRow              m_row;
};


int main()
{
    std::ifstream       file("plop.csv");

    for(CSVIterator loop(file); loop != CSVIterator(); ++loop)
    {
        std::cout << "4th Element(" << (*loop)[3] << ")\n";
    }
}

20
প্রথম () পরবর্তী ()। এই জাভা কি! শুধুই মজা করার জন্য.
মার্টিন ইয়র্ক

4
@ দার্থভেদার: একটি ওভারলে বিস্তৃত বিবৃতি যে এর প্রশস্ততা দ্বারা নির্বোধ। আপনি যদি এটি পরিষ্কার করতে চান যে এটি কেন খারাপ এবং তারপরে কেন এই প্রবণতাটি এই প্রসঙ্গে প্রযোজ্য।
মার্টিন ইয়র্ক

12
@ দার্থভেদার: আমি মনে করি বিস্তৃত সাধারণীকরণ করা বোকামি। উপরের কোডটি সঠিকভাবে কাজ করে যাতে আমি এটিতে আসলে কোনও ভুল দেখতে পাই। তবে উপরোক্ত বিষয়ে আপনার কোনও নির্দিষ্ট মন্তব্য থাকলে আমি অবশ্যই এই প্রসঙ্গে বিবেচনা করব। তবে আমি দেখতে পাচ্ছি যে আপনি সি # এর জন্য সাধারণীকরণের নিয়মের একটি সেট মানসিকভাবে অনুসরণ করে এবং অন্য ভাষায় প্রয়োগ করে কীভাবে এই সিদ্ধান্তে আসতে পারেন।
মার্টিন ইয়র্ক

5
এছাড়াও, যদি আপনি উপরের কোডটির সাথে অদ্ভুত সংযোগ সমস্যাগুলিতে চলে যান কারণ অন্য কোনও গ্রন্থাগার কোথাও সংজ্ঞা দেয় istream::operator>>(আইগেনের মতো), inlineএটি ঠিক করার জন্য অপারেটরের ঘোষণার আগে একটি যুক্ত করুন ।
সেবাস্তিয়ান_কে

3
আমি যে কোনও পুনরাবৃত্ত শ্রেণি তৈরি করেছি তার কী এটি সহজ এবং পরিষ্কার উদাহরণ।
জিয়ানকার্লো স্পোর্টেলি

46

বুস্ট টোকেনাইজার ব্যবহার করে সমাধান:

std::vector<std::string> vec;
using namespace boost;
tokenizer<escaped_list_separator<char> > tk(
   line, escaped_list_separator<char>('\\', ',', '\"'));
for (tokenizer<escaped_list_separator<char> >::iterator i(tk.begin());
   i!=tk.end();++i) 
{
   vec.push_back(*i);
}

9
বুস্ট টোকেনাইজার সম্পূর্ণ সিএসভি স্ট্যান্ডার্ডকে পুরোপুরি সমর্থন করে না, তবে কয়েকটি দ্রুত কাজের ক্ষেত্র রয়েছে। স্ট্যাকওভারফ্লো
রল্ফ ক্রিস্টেনসেন

3
আপনার মেশিনে পুরো বুস্ট লাইব্রেরি থাকতে হবে, না আপনি এটি করতে তাদের কোডের একটি উপসেট ব্যবহার করতে পারেন? সিএসভি পার্সিংয়ের জন্য 256 এমবি অনেকটা মনে হচ্ছে ..
এনপাইক

6
@NPike: আপনি ব্যবহার করতে পারেন BCP উপযোগ যে বুস্ট দিয়ে আসে শুধুমাত্র হেডার আপনি আসলে প্রয়োজন বের করে আনতে।
iljarn

46

আমার সংস্করণটি স্ট্যান্ডার্ড সি ++ 11 লাইব্রেরি ছাড়া আর কিছু ব্যবহার করছে না। এটি এক্সেল সিএসভি উদ্ধৃতি সহ ভাল কপি করে:

spam eggs,"foo,bar","""fizz buzz"""
1.23,4.567,-8.00E+09

কোডটি সসীম-রাষ্ট্র মেশিন হিসাবে লেখা এবং একসাথে একটি অক্ষর গ্রাস করে। আমি মনে করি এটি সম্পর্কে তর্ক করা সহজ।

#include <istream>
#include <string>
#include <vector>

enum class CSVState {
    UnquotedField,
    QuotedField,
    QuotedQuote
};

std::vector<std::string> readCSVRow(const std::string &row) {
    CSVState state = CSVState::UnquotedField;
    std::vector<std::string> fields {""};
    size_t i = 0; // index of the current field
    for (char c : row) {
        switch (state) {
            case CSVState::UnquotedField:
                switch (c) {
                    case ',': // end of field
                              fields.push_back(""); i++;
                              break;
                    case '"': state = CSVState::QuotedField;
                              break;
                    default:  fields[i].push_back(c);
                              break; }
                break;
            case CSVState::QuotedField:
                switch (c) {
                    case '"': state = CSVState::QuotedQuote;
                              break;
                    default:  fields[i].push_back(c);
                              break; }
                break;
            case CSVState::QuotedQuote:
                switch (c) {
                    case ',': // , after closing quote
                              fields.push_back(""); i++;
                              state = CSVState::UnquotedField;
                              break;
                    case '"': // "" -> "
                              fields[i].push_back('"');
                              state = CSVState::QuotedField;
                              break;
                    default:  // end of quote
                              state = CSVState::UnquotedField;
                              break; }
                break;
        }
    }
    return fields;
}

/// Read CSV file, Excel dialect. Accept "quoted fields ""with quotes"""
std::vector<std::vector<std::string>> readCSV(std::istream &in) {
    std::vector<std::vector<std::string>> table;
    std::string row;
    while (!in.eof()) {
        std::getline(in, row);
        if (in.bad() || in.fail()) {
            break;
        }
        auto fields = readCSVRow(row);
        table.push_back(fields);
    }
    return table;
}

6
ধন্যবাদ, আমি মনে করি এটি সবচেয়ে সম্পূর্ণ উত্তর, খুব খারাপ এটি এখানে সমাহিত হয়েছে।
মিহাই

স্ট্রিংগুলির এই নেস্টেড ভেক্টরটি আধুনিক প্রসেসরগুলির জন্য অচল। তাদের
ক্যাচিংয়ের

প্লাস আপনি এই সমস্ত স্যুইচ স্টেটমেন্ট পেয়েছেন
নিকোলোস গিয়টিস

উপরের উত্তরটি আমার পক্ষে কার্যকর হয়নি, কারণ আমি একজন পুরনো সংকলক আছি। এই উত্তরটি কার্যকর হয়েছে, ভেক্টর const char *vinit[] = {""}; vector<string> fields(vinit, end(vinit));
সূচনাটির জন্য এটির

31

সি ++ স্ট্রিং টুলকিট লাইব্রেরি (StrTk) একটি টোকেন গ্রিড বর্গ যে আপনার কাছ থেকে পারেন ডেটা লোড রাখার মঞ্জুরি দেয় টেক্সট ফাইল, স্ট্রিং বা গৃহস্থালির কাজ বাফার একটি সারিতে-কলাম ফ্যাশন, এবং তাদের পার্স / প্রক্রিয়া।

আপনি সারি ডিলিমিটার এবং কলাম ডিলিমিটারগুলি নির্দিষ্ট করতে পারেন বা কেবল ডিফল্ট ব্যবহার করতে পারেন।

void foo()
{
   std::string data = "1,2,3,4,5\n"
                      "0,2,4,6,8\n"
                      "1,3,5,7,9\n";

   strtk::token_grid grid(data,data.size(),",");

   for(std::size_t i = 0; i < grid.row_count(); ++i)
   {
      strtk::token_grid::row_type r = grid.row(i);
      for(std::size_t j = 0; j < r.size(); ++j)
      {
         std::cout << r.get<int>(j) << "\t";
      }
      std::cout << std::endl;
   }
   std::cout << std::endl;
}

আরও উদাহরণ এখানে পাওয়া যাবে


1
যদিও strtk ডাবলকোয়েটেড ক্ষেত্রগুলিকে সমর্থন করে এবং এমনকি আশেপাশের উদ্ধৃতিগুলি (মাধ্যমে options.trim_dquotes = true) সরিয়ে দিচ্ছে, এটি দ্বিগুণ ডাবলকোটগুলি (যেমন ক্ষেত্রটিকে "She said ""oh no"", and left."সি-স্ট্রিং হিসাবে "She said \"oh no\", and left.") সরানোর পক্ষে সমর্থন করে না । আপনি নিজে এটি করতে হবে।
রায়পুমান

1
ব্যবহার করার সময় strtk, আপনাকে ডাবল-উদ্ধৃত ক্ষেত্রগুলিতে ম্যানুয়ালি হ্যান্ডেল করতে হবে যাতে নিউলাইন অক্ষর রয়েছে।
রামপিন

29

আপনি পালানো_লিস্ট_সেস্পেটর সহ বুস্ট টোকেনাইজার ব্যবহার করতে পারেন।

Escape_list_separator csv এর একটি সুপারসেট পার্স করে। বুস্ট :: tokenizer

এটি কেবল বুস্ট টোকেনাইজার হেডার ফাইল ব্যবহার করে, লাইব্রেরিগুলিকে বুস্ট করার জন্য কোনও লিঙ্কের প্রয়োজন নেই inking

এখানে একটি উদাহরণ দেওয়া হয়েছে, ( বিশদের জন্য C ++ এ বুস্ট টোকেনাইজারের সাথে সিএসভি ফাইল পার্স করুন বা দেখুন Boost::tokenizer):

#include <iostream>     // cout, endl
#include <fstream>      // fstream
#include <vector>
#include <string>
#include <algorithm>    // copy
#include <iterator>     // ostream_operator
#include <boost/tokenizer.hpp>

int main()
{
    using namespace std;
    using namespace boost;
    string data("data.csv");

    ifstream in(data.c_str());
    if (!in.is_open()) return 1;

    typedef tokenizer< escaped_list_separator<char> > Tokenizer;
    vector< string > vec;
    string line;

    while (getline(in,line))
    {
        Tokenizer tok(line);
        vec.assign(tok.begin(),tok.end());

        // vector now contains strings from one row, output to cout here
        copy(vec.begin(), vec.end(), ostream_iterator<string>(cout, "|"));

        cout << "\n----------------------" << endl;
    }
}

এবং আপনি যদি এম্বেড করা নতুন লাইনগুলি mybyteofcode.blogspot.com/2010/11/… পার্স করতে সক্ষম হতে চান ।
স্টেফানবি

এই কৌশলটি কাজ করার সময়, আমি এটি খুব খারাপ পারফরম্যান্স পেয়েছি। প্রতি লাইনে দশটি ক্ষেত্রের সাথে 90000 লাইনের সিএসভি ফাইলটি পার্স করা আমার 2 গিগাহার্জ জিয়োন প্রায় 8 সেকেন্ড সময় নেয়। পাইথন স্ট্যান্ডার্ড লাইব্রেরি সিএসভি মডিউল একই ফাইলটিকে প্রায় 0.3 সেকেন্ডের মধ্যে পার্স করে।
রব স্মলশায়ার

@ রব এটি আকর্ষণীয় - পাইথন সিএসভি আলাদাভাবে কী করে?
তোফুটিম

1
@ রবসম্লশায়ার এটি একটি সাধারণ উদাহরণ কোড যা উচ্চ কার্যকারিতা নয় one এই কোডটি প্রতি লাইনে সমস্ত ক্ষেত্রের অনুলিপি তৈরি করে। উচ্চতর পারফরম্যান্সের জন্য আপনি বিভিন্ন বিকল্প ব্যবহার করবেন এবং অনুলিপি তৈরির পরিবর্তে বাফারের ক্ষেত্রগুলিতে কেবল উল্লেখগুলি ফিরিয়ে আনবেন।
স্টিফানবি

29

সিএসভিগুলিকে পার্স করার জন্য স্পিরিট ব্যবহার করা অত্যধিক দক্ষতা নয়। স্পিরিট মাইক্রো-পার্সিং কার্যগুলির জন্য উপযুক্ত। উদাহরণস্বরূপ, স্পিরিট ২.১ সহ এটি এতটা সহজ:

bool r = phrase_parse(first, last,

    //  Begin grammar
    (
        double_ % ','
    )
    ,
    //  End grammar

    space, v);

ভেক্টর, ভ, মান সহ স্টাফ হয়ে যায়। নতুন স্পিরিট ২.১ ডক্সে এটিকে স্পর্শ করে একটি টিউটোরিয়াল রয়েছে যা বুস্ট ১.৪১ সহ সবে প্রকাশ হয়েছে।

টিউটোরিয়ালটি সহজ থেকে জটিল পর্যন্ত এগিয়ে যায়। সিএসভি পার্সারগুলি মাঝখানে কোথাও উপস্থাপিত হয় এবং স্পিরিট ব্যবহারের বিভিন্ন কৌশলগুলিতে স্পর্শ করে। উত্পন্ন কোডটি হাতের লিখিত কোডের মতো শক্ত। উত্পন্ন সমাবেশটি দেখুন!


18
প্রকৃতপক্ষে এটি ওভারকিল, সংকলনের সময় হিট প্রচুর এবং সাধারণ "মাইক্রো-পার্সিং কার্যগুলির জন্য" স্পিরিটকে অযৌক্তিক করে তোলে।
গার্ডিনার

13
এছাড়াও আমি এটি উল্লেখ করতে চাই যে উপরের কোডটি সিএসভিকে বিশ্লেষণ করে না, এটি কমা দ্বারা বিসর্জনিত ভেক্টরের ধরণের একটি অংশকে পার্স করে। এটি কোট, বিভিন্ন ধরণের কলাম ইত্যাদি হ্যান্ডেল করে না, সংক্ষিপ্ত 19 ভোটে এমন প্রশ্নের জন্য যা মোটেও প্রশ্নের উত্তর দেয় তা আমার কাছে কিছুটা সন্দেহজনক বলে মনে হয়।
গার্ডিনার

9
পুনঃটুইট ছোট পার্সারদের জন্য সংকলনের সময়টি এত বড় নয়, তবে এটি অপ্রাসঙ্গিক কারণ আপনি কোডটিকে তার নিজস্ব সংকলন ইউনিটে স্টাফ করেন এবং একবার এটি সংকলন করেন । তারপরে আপনাকে কেবল এটির লিঙ্ক করতে হবে এবং এটি যতটা দক্ষ তা কার্যকর। এবং আপনার অন্যান্য মন্তব্যে, এর জন্য প্রসেসর রয়েছে এমন অনেকগুলি সিএসভির উপভাষা রয়েছে। এটি অবশ্যই খুব দরকারী উপভাষা নয় তবে উদ্ধৃত মানগুলি হ্যান্ডেল করার জন্য এটি তুচ্ছভাবে বাড়ানো যেতে পারে।
কনরাড রুডল্ফ

11
@ কোনরাদ: খালি ফাইলটিতে কেবলমাত্র একটি মূল সহ "# অন্তর্ভুক্ত <বুস্ট / স্পিরিট / অন্তর্ভুক্ত / কিউইকিপিপি>" অন্তর্ভুক্ত এবং অন্য কোনও কিছুই এমএসভিসি ২০১২-এর সাথে ৯.gh জিজেডে চলমান একটি কোরআইতে 9.7 সেকেন্ড লাগে না। এটি অকারণে ফুলে যাওয়া। গৃহীত উত্তরগুলি একই মেশিনে 2 সেকেন্ডের আওতায় সংকলিত হয়, আমি 'যথাযথ' বুস্ট.স্পিরিট উদাহরণটি সংকলন করতে কত সময় নিবে তা কল্পনা করতে ঘৃণা করব।
গার্ডিনার

11
@ গ্রেডিনার সিভিএস প্রসেসিংয়ের চেয়ে সহজ কিছু হিসাবে স্পিরিট ব্যবহার করার জন্য আপনাকে ওভারহেডের সাথে আমি একমত হতে হবে।

18

আপনি যদি DO করা CSV সঠিকভাবে পার্স সম্পর্কে যত্ন, এই এটা করতে হবে ... অপেক্ষাকৃত ধীরে ধীরে যেমন একটি সময়ে এক গৃহস্থালির কাজ কাজ করে।

 void ParseCSV(const string& csvSource, vector<vector<string> >& lines)
    {
       bool inQuote(false);
       bool newLine(false);
       string field;
       lines.clear();
       vector<string> line;

       string::const_iterator aChar = csvSource.begin();
       while (aChar != csvSource.end())
       {
          switch (*aChar)
          {
          case '"':
             newLine = false;
             inQuote = !inQuote;
             break;

          case ',':
             newLine = false;
             if (inQuote == true)
             {
                field += *aChar;
             }
             else
             {
                line.push_back(field);
                field.clear();
             }
             break;

          case '\n':
          case '\r':
             if (inQuote == true)
             {
                field += *aChar;
             }
             else
             {
                if (newLine == false)
                {
                   line.push_back(field);
                   lines.push_back(line);
                   field.clear();
                   line.clear();
                   newLine = true;
                }
             }
             break;

          default:
             newLine = false;
             field.push_back(*aChar);
             break;
          }

          aChar++;
       }

       if (field.size())
          line.push_back(field);

       if (line.size())
          lines.push_back(line);
    }

AFAICT এটি এমবেডেড উদ্ধৃতি চিহ্নগুলি সঠিকভাবে পরিচালনা করবে না (উদাঃ "এই স্ট্রিংটিতে" "এম্বেড করা উদ্ধৃতি চিহ্ন রয়েছে" "", "ফু", 1))
জেরেমি ফ্রাইজনার

14

সিএসভি ফাইলগুলির জন্য বুস্ট টোকেনাইজার এসিডে_লিস্ট_সেস্পেটর ব্যবহার করার সময়, নিম্নলিখিত বিষয় সম্পর্কে আপনার সচেতন হওয়া উচিত:

  1. এটির জন্য একটি পালানোর অক্ষর প্রয়োজন (ডিফল্ট ব্যাক-স্ল্যাশ - \)
  2. এর জন্য একটি বিভাজনকারী / পৃথক-চরিত্রের প্রয়োজন (ডিফল্ট কমা -,)
  3. এটিতে একটি উদ্ধৃতি-অক্ষর প্রয়োজন (ডিফল্ট উদ্ধৃতি - ")

উইকির দ্বারা নির্দিষ্ট করা সিএসভি ফর্ম্যাটতে বলা হয়েছে যে ডেটা ফিল্ডগুলিতে কোট (সমর্থিত) এ বিভাজক থাকতে পারে:

1997, ফোর্ড, E350, "সুপার, বিলাসবহুল ট্রাক"

উইকির দ্বারা নির্ধারিত সিএসভি ফর্ম্যাটতে বলা হয়েছে যে একক উদ্ধৃতিগুলি ডাবল-কোট দিয়ে পরিচালনা করা উচিত (পলায়ন_ তালিকা_ সেপারেটর সমস্ত উদ্ধৃতি অক্ষর সরিয়ে ফেলবে):

1997, ফোর্ড, E350, "সুপার" "বিলাসবহুল" "ট্রাক"

সিএসভি ফর্ম্যাটটি নির্দিষ্ট করে না যে কোনও ব্যাক-স্ল্যাশ অক্ষর দূরে সরিয়ে নেওয়া উচিত (এস্কেপড_লিস্ট_সেস্পেরেটর সমস্ত পালানোর অক্ষর সরিয়ে ফেলবে)।

বুস্ট এস্কেপড_লিস্ট_সেপারেটরের ডিফল্ট আচরণটি ঠিক করার জন্য একটি সম্ভাব্য ওয়ার্ক-এয়ার:

  1. প্রথমে সমস্ত ব্যাক-স্ল্যাশ অক্ষর (\) দুটি ব্যাক-স্ল্যাশ অক্ষর (\\) দিয়ে প্রতিস্থাপন করুন যাতে সেগুলি এড়ানো যায় না।
  2. দ্বিতীয়ত সমস্ত ডাবল-কোট ("") একক ব্যাক-স্ল্যাশ অক্ষর এবং একটি উদ্ধৃতি (\ ") এর সাথে প্রতিস্থাপন করুন

এই কাজের চারপাশে পার্শ্ব-প্রতিক্রিয়া রয়েছে যে খালি ডেটা-ক্ষেত্রগুলি যা ডাবল-কোট দ্বারা উপস্থাপিত হয়, একটি একক-উদ্ধৃতি-টোকনে রূপান্তরিত হবে। টোকেনগুলির মধ্য দিয়ে পুনরাবৃত্তি করার সময়, টোকনটি একক-উদ্ধৃতি কিনা তা অবশ্যই পরীক্ষা করা উচিত এবং এটিকে খালি স্ট্রিংয়ের মতো আচরণ করা উচিত।

সুন্দর না তবে এটি কাজ করে, যতক্ষণ উদ্ধৃতিগুলির মধ্যে নতুন লাইনের উপস্থিতি নেই।


8

আপনি আমার FOSS প্রকল্প CSVfix ( আপডেট লিঙ্ক) দেখতে চাইতে পারেন ) দেখতে চান, যা সি ++ তে লেখা CSV স্ট্রিম সম্পাদক। সিএসভি পার্সার কোনও পুরষ্কার নয়, তবে কাজটি এবং পুরো প্যাকেজটি কোনও কোড না লিখে আপনার যা প্রয়োজন তা করতে পারে।

দেখুন Alib / src / a_csv.cpp করা CSV পার্সার জন্য, এবং csvlib / src / csved_ioman.cpp ( IOManager::ReadCSV) একটি ব্যবহার উদাহরণস্বরূপ।


দুর্দান্ত মনে হচ্ছে ... স্ট্যাটাস বিটা / প্রোডাকশন সম্পর্কে কী?
নিউরো

সংস্করণ সংখ্যাগুলি দ্বারা প্রস্তাবিত হিসাবে স্থিতিটি "বিকাশে"। 1.0 সংস্করণে যাওয়ার আগে ব্যবহারকারীদের থেকে আমার সত্যিই আরও ফিড দরকার। প্লাস আমার সিএসভি থেকে এক্সএমএল উত্পাদন করতে আরও কয়েকটি বৈশিষ্ট্য যুক্ত করতে চাই।

এটি বুকমার্কিং, এবং পরের বার আমাকে সেই দুর্দান্ত স্ট্যান্ডার্ড সিএসভি ফাইলগুলির সাথে ডিল করতে হবে ...
নিউরো

8

যেহেতু সমস্ত সিএসভি প্রশ্ন এখানে পুনঃনির্দেশিত হয়েছে বলে মনে হয়েছে, আমি আমার উত্তর এখানে পোস্ট করব। এই উত্তরটি সরাসরি প্রশ্নকারীর প্রশ্নের সমাধান করে না। আমি সিএসভি ফর্ম্যাটে পরিচিত এমন স্ট্রিমে পড়তে সক্ষম হতে চেয়েছি এবং প্রতিটি ক্ষেত্রের প্রকারগুলি ইতিমধ্যে জানা ছিল। অবশ্যই, নীচের পদ্ধতিটি প্রতিটি ক্ষেত্রকে একটি স্ট্রিং ধরণের হিসাবে বিবেচনা করতে ব্যবহার করা যেতে পারে।

আমি কীভাবে একটি সিএসভি ইনপুট স্ট্রিমটি ব্যবহার করতে সক্ষম হতে চেয়েছিলাম তার উদাহরণ হিসাবে, নিম্নলিখিত ইনপুটটি বিবেচনা করুন ( সিএসভিতে উইকিপিডিয়া পৃষ্ঠা থেকে নেওয়া ):

const char input[] =
"Year,Make,Model,Description,Price\n"
"1997,Ford,E350,\"ac, abs, moon\",3000.00\n"
"1999,Chevy,\"Venture \"\"Extended Edition\"\"\",\"\",4900.00\n"
"1999,Chevy,\"Venture \"\"Extended Edition, Very Large\"\"\",\"\",5000.00\n"
"1996,Jeep,Grand Cherokee,\"MUST SELL!\n\
air, moon roof, loaded\",4799.00\n"
;

তারপরে, আমি এই জাতীয় ডেটাতে পড়তে সক্ষম হতে চেয়েছিলাম:

std::istringstream ss(input);
std::string title[5];
int year;
std::string make, model, desc;
float price;
csv_istream(ss)
    >> title[0] >> title[1] >> title[2] >> title[3] >> title[4];
while (csv_istream(ss)
       >> year >> make >> model >> desc >> price) {
    //...do something with the record...
}

এই সমাধানটি আমি শেষ করেছিলাম।

struct csv_istream {
    std::istream &is_;
    csv_istream (std::istream &is) : is_(is) {}
    void scan_ws () const {
        while (is_.good()) {
            int c = is_.peek();
            if (c != ' ' && c != '\t') break;
            is_.get();
        }
    }
    void scan (std::string *s = 0) const {
        std::string ws;
        int c = is_.get();
        if (is_.good()) {
            do {
                if (c == ',' || c == '\n') break;
                if (s) {
                    ws += c;
                    if (c != ' ' && c != '\t') {
                        *s += ws;
                        ws.clear();
                    }
                }
                c = is_.get();
            } while (is_.good());
            if (is_.eof()) is_.clear();
        }
    }
    template <typename T, bool> struct set_value {
        void operator () (std::string in, T &v) const {
            std::istringstream(in) >> v;
        }
    };
    template <typename T> struct set_value<T, true> {
        template <bool SIGNED> void convert (std::string in, T &v) const {
            if (SIGNED) v = ::strtoll(in.c_str(), 0, 0);
            else v = ::strtoull(in.c_str(), 0, 0);
        }
        void operator () (std::string in, T &v) const {
            convert<is_signed_int<T>::val>(in, v);
        }
    };
    template <typename T> const csv_istream & operator >> (T &v) const {
        std::string tmp;
        scan(&tmp);
        set_value<T, is_int<T>::val>()(tmp, v);
        return *this;
    }
    const csv_istream & operator >> (std::string &v) const {
        v.clear();
        scan_ws();
        if (is_.peek() != '"') scan(&v);
        else {
            std::string tmp;
            is_.get();
            std::getline(is_, tmp, '"');
            while (is_.peek() == '"') {
                v += tmp;
                v += is_.get();
                std::getline(is_, tmp, '"');
            }
            v += tmp;
            scan();
        }
        return *this;
    }
    template <typename T>
    const csv_istream & operator >> (T &(*manip)(T &)) const {
        is_ >> manip;
        return *this;
    }
    operator bool () const { return !is_.fail(); }
};

নিম্নলিখিত সহায়কগুলির সাথে যা সি ++ 11 এ নতুন অবিচ্ছেদ্য বৈশিষ্ট্য টেমপ্লেটগুলি দ্বারা সরল করা যেতে পারে:

template <typename T> struct is_signed_int { enum { val = false }; };
template <> struct is_signed_int<short> { enum { val = true}; };
template <> struct is_signed_int<int> { enum { val = true}; };
template <> struct is_signed_int<long> { enum { val = true}; };
template <> struct is_signed_int<long long> { enum { val = true}; };

template <typename T> struct is_unsigned_int { enum { val = false }; };
template <> struct is_unsigned_int<unsigned short> { enum { val = true}; };
template <> struct is_unsigned_int<unsigned int> { enum { val = true}; };
template <> struct is_unsigned_int<unsigned long> { enum { val = true}; };
template <> struct is_unsigned_int<unsigned long long> { enum { val = true}; };

template <typename T> struct is_int {
    enum { val = (is_signed_int<T>::val || is_unsigned_int<T>::val) };
};

এটি অনলাইন চেষ্টা করুন!


6

আমি কেবল একটি শিরোনাম লিখেছি, সি ++ 11 সিএসভি পার্সার । এটি ভালভাবে পরীক্ষিত, দ্রুত, পুরো সিএসভি বিশেষকে (উদ্ধৃত ক্ষেত্রগুলি, উদ্ধৃতিগুলিতে ডিলিমিটার / টার্মিনেটর, উদ্ধৃতি অব্যাহতি ইত্যাদি) সমর্থন করে এবং সিএসভিগুলির জন্য অ্যাকাউন্টে কনফিগারযোগ্য যা স্পেসিফিকেশন মেনে চলে না।

কনফিগারেশন একটি সাবলীল ইন্টারফেসের মাধ্যমে সম্পন্ন করা হয়:

// constructor accepts any input stream
CsvParser parser = CsvParser(std::cin)
  .delimiter(';')    // delimited by ; instead of ,
  .quote('\'')       // quoted fields use ' instead of "
  .terminator('\0'); // terminated by \0 instead of by \r\n, \n, or \r

লুপের জন্য পার্সিং করা কেবলমাত্র একটি ব্যাপ্তি:

#include <iostream>
#include "../parser.hpp"

using namespace aria::csv;

int main() {
  std::ifstream f("some_file.csv");
  CsvParser parser(f);

  for (auto& row : parser) {
    for (auto& field : row) {
      std::cout << field << " | ";
    }
    std::cout << std::endl;
  }
}

1
দুর্দান্ত কাজ, তবে আপনাকে আরও তিনটি জিনিস যুক্ত করতে হবে: (১) পঠন শিরোলেখ (২) নাম অনুসারে ক্ষেত্রগুলি সরবরাহ করুন (3) একই স্ট্রিংয়ের
স্ট্রাক্ট

@ ম্যাক্সেমগ্যানেনকো আমি # 3 করি। আপনি # 2 এ বিস্তারিত বলতে পারেন?
m0meni

1
এটি সারিবদ্ধভাবে অবস্থানের ভিত্তিতে নয়, তবে শিরোনামে (সিএসভি সারণীর প্রথম সারিতে) দেওয়া নাম দিয়ে ক্ষেত্রগুলি পাওয়া খুব দরকারী। উদাহরণস্বরূপ, আমি "তারিখ" ক্ষেত্র সহ সিএসভি সারণীটি প্রত্যাশা করি, তবে পরের দিকে "তারিখ" ফিল্ড সূচী কী তা আমি জানি না।
ম্যাকসিম গ্যানেনকো

1
@ ম্যাক্সেমগ্যানেনকো আহ আমি দেখছি আপনি কী বলতে চাইছেন। সংকলনের সময় আপনি যখন নিজের সিএসভি-র কলামগুলি জানবেন তখন এর জন্য github.com/ben-strasser/ ব্রেকফাস্ট-cpp - csv - parser রয়েছে এবং এটি আমার থেকে সম্ভবত ভাল। আমি যা চেয়েছিলাম তা সেই ক্ষেত্রে CSV পার্সার ছিল যেখানে আপনি অনেকগুলি বিভিন্ন সিএসভিতে একই কোডটি ব্যবহার করতে চেয়েছিলেন এবং জানেন না যে তারা সময়ের চেয়ে আগে কী দেখাচ্ছে। সুতরাং আমি সম্ভবত # 2 যোগ করব না, তবে ভবিষ্যতে আমি 1 টি যোগ করব।
এম0meni

5

অন্য একটি সিএসভি আই / ও লাইব্রেরি এখানে পাওয়া যাবে:

http://code.google.com/p/fast-cpp-csv-parser/

#include "csv.h"

int main(){
  io::CSVReader<3> in("ram.csv");
  in.read_header(io::ignore_extra_column, "vendor", "size", "speed");
  std::string vendor; int size; double speed;
  while(in.read_row(vendor, size, speed)){
    // do stuff with the data
  }
}

2
দুর্দান্ত, তবে এটি আপনাকে সংকলনের সময় কলামগুলির সংখ্যা চয়ন করতে বাধ্য করে। অনেক অ্যাপ্লিকেশন জন্য খুব দরকারী নয়।
কোয়ান্ট_দেব

5

লোকি আস্তারির উত্তরের অনুরূপ আর একটি সমাধান , সি ++ 11 এ। সারিগুলি এখানে std::tupleপ্রদত্ত প্রকারের। কোডটি একটি লাইন স্ক্যান করে, তারপরে প্রতিটি ডিলিমিটার পর্যন্ত স্ক্যান করে এবং তারপরে মানটিকে রূপান্তরিত করে এবং সরাসরি টুপলে (কিছুটা টেম্পলেট কোড দিয়ে) ডাম্প করে।

for (auto row : csv<std::string, int, float>(file, ',')) {
    std::cout << "first col: " << std::get<0>(row) << std::endl;
}

Advanges:

  • বেশ পরিষ্কার এবং সহজেই ব্যবহারযোগ্য, কেবল সি ++ 11।
  • এর std::tuple<t1, ...>মাধ্যমে স্বয়ংক্রিয় ধরণের রূপান্তর operator>>

কি অনুপস্থিত:

  • পলায়ন এবং উদ্ধৃতি
  • ত্রুটিযুক্ত সিএসভি ক্ষেত্রে কোনও ত্রুটি পরিচালনার দরকার নেই।

প্রধান কোড:

#include <iterator>
#include <sstream>
#include <string>

namespace csvtools {
    /// Read the last element of the tuple without calling recursively
    template <std::size_t idx, class... fields>
    typename std::enable_if<idx >= std::tuple_size<std::tuple<fields...>>::value - 1>::type
    read_tuple(std::istream &in, std::tuple<fields...> &out, const char delimiter) {
        std::string cell;
        std::getline(in, cell, delimiter);
        std::stringstream cell_stream(cell);
        cell_stream >> std::get<idx>(out);
    }

    /// Read the @p idx-th element of the tuple and then calls itself with @p idx + 1 to
    /// read the next element of the tuple. Automatically falls in the previous case when
    /// reaches the last element of the tuple thanks to enable_if
    template <std::size_t idx, class... fields>
    typename std::enable_if<idx < std::tuple_size<std::tuple<fields...>>::value - 1>::type
    read_tuple(std::istream &in, std::tuple<fields...> &out, const char delimiter) {
        std::string cell;
        std::getline(in, cell, delimiter);
        std::stringstream cell_stream(cell);
        cell_stream >> std::get<idx>(out);
        read_tuple<idx + 1, fields...>(in, out, delimiter);
    }
}

/// Iterable csv wrapper around a stream. @p fields the list of types that form up a row.
template <class... fields>
class csv {
    std::istream &_in;
    const char _delim;
public:
    typedef std::tuple<fields...> value_type;
    class iterator;

    /// Construct from a stream.
    inline csv(std::istream &in, const char delim) : _in(in), _delim(delim) {}

    /// Status of the underlying stream
    /// @{
    inline bool good() const {
        return _in.good();
    }
    inline const std::istream &underlying_stream() const {
        return _in;
    }
    /// @}

    inline iterator begin();
    inline iterator end();
private:

    /// Reads a line into a stringstream, and then reads the line into a tuple, that is returned
    inline value_type read_row() {
        std::string line;
        std::getline(_in, line);
        std::stringstream line_stream(line);
        std::tuple<fields...> retval;
        csvtools::read_tuple<0, fields...>(line_stream, retval, _delim);
        return retval;
    }
};

/// Iterator; just calls recursively @ref csv::read_row and stores the result.
template <class... fields>
class csv<fields...>::iterator {
    csv::value_type _row;
    csv *_parent;
public:
    typedef std::input_iterator_tag iterator_category;
    typedef csv::value_type         value_type;
    typedef std::size_t             difference_type;
    typedef csv::value_type *       pointer;
    typedef csv::value_type &       reference;

    /// Construct an empty/end iterator
    inline iterator() : _parent(nullptr) {}
    /// Construct an iterator at the beginning of the @p parent csv object.
    inline iterator(csv &parent) : _parent(parent.good() ? &parent : nullptr) {
        ++(*this);
    }

    /// Read one row, if possible. Set to end if parent is not good anymore.
    inline iterator &operator++() {
        if (_parent != nullptr) {
            _row = _parent->read_row();
            if (!_parent->good()) {
                _parent = nullptr;
            }
        }
        return *this;
    }

    inline iterator operator++(int) {
        iterator copy = *this;
        ++(*this);
        return copy;
    }

    inline csv::value_type const &operator*() const {
        return _row;
    }

    inline csv::value_type const *operator->() const {
        return &_row;
    }

    bool operator==(iterator const &other) {
        return (this == &other) or (_parent == nullptr and other._parent == nullptr);
    }
    bool operator!=(iterator const &other) {
        return not (*this == other);
    }
};

template <class... fields>
typename csv<fields...>::iterator csv<fields...>::begin() {
    return iterator(*this);
}

template <class... fields>
typename csv<fields...>::iterator csv<fields...>::end() {
    return iterator();
}

আমি গিটহাবের উপর একটি ক্ষুদ্র কাজের উদাহরণ রেখেছি ; আমি কিছু সংখ্যক ডেটা পার্স করার জন্য এটি ব্যবহার করছি এবং এটি তার উদ্দেশ্যটি সম্পাদন করেছে।


1
আপনি ইনলাইনিংয়ের বিষয়ে চিন্তা করতে পারেন না, কারণ বেশিরভাগ সংকলক এটি নিজের সিদ্ধান্ত নেন। কমপক্ষে আমি ভিজ্যুয়াল সি ++ এ নিশ্চিত। এটি আপনার পদ্ধতির নির্দিষ্টকরণের স্বাধীনভাবে পদ্ধতিটিকে ইনলাইন করতে পারে।
মিঃপিসারিক

1
এই কারণেই আমি তাদের স্পষ্টভাবে চিহ্নিত করেছি। জিসিসি এবং ক্ল্যাং, আমি বেশিরভাগই ব্যবহার করি, পাশাপাশি তাদের নিজস্ব কনভেনশন রয়েছে। একটি "ইনলাইন" কীওয়ার্ডটি কেবল একটি প্রণোদনা হওয়া উচিত।
স্পেক

4

এখানে একটি ইউনিকোড সিএসভি পার্সার (wchar_t দিয়ে কাজ করে) এর আরও একটি বাস্তবায়ন। আমি এর একটি অংশ লিখেছি, অন্যদিকে জোনাথন লেফলার লিখেছেন।

দ্রষ্টব্য: এই পার্সারটি এক্সেলের আচরণকে যথাসম্ভব ঘনিষ্ঠভাবে প্রতিস্থাপনের উদ্দেশ্যে করা হয়েছে, বিশেষত ভাঙা বা ত্রুটিযুক্ত সিএসভি ফাইল আমদানি করার সময় ।

এটিই আসল প্রশ্ন - বহু লাইন ক্ষেত্রগুলির সাথে সিএসভি ফাইল পার্সিং করা এবং ডাবল উদ্ধৃতিগুলি রক্ষা করা

এটি একটি এসএসসিসিই (সংক্ষিপ্ত, স্ব-অন্তর্ভুক্ত, সঠিক উদাহরণ) হিসাবে কোড।

#include <stdbool.h>
#include <wchar.h>
#include <wctype.h>

extern const wchar_t *nextCsvField(const wchar_t *p, wchar_t sep, bool *newline);

// Returns a pointer to the start of the next field,
// or zero if this is the last field in the CSV
// p is the start position of the field
// sep is the separator used, i.e. comma or semicolon
// newline says whether the field ends with a newline or with a comma
const wchar_t *nextCsvField(const wchar_t *p, wchar_t sep, bool *newline)
{
    // Parse quoted sequences
    if ('"' == p[0]) {
        p++;
        while (1) {
            // Find next double-quote
            p = wcschr(p, L'"');
            // If we don't find it or it's the last symbol
            // then this is the last field
            if (!p || !p[1])
                return 0;
            // Check for "", it is an escaped double-quote
            if (p[1] != '"')
                break;
            // Skip the escaped double-quote
            p += 2;
        }
    }

    // Find next newline or comma.
    wchar_t newline_or_sep[4] = L"\n\r ";
    newline_or_sep[2] = sep;
    p = wcspbrk(p, newline_or_sep);

    // If no newline or separator, this is the last field.
    if (!p)
        return 0;

    // Check if we had newline.
    *newline = (p[0] == '\r' || p[0] == '\n');

    // Handle "\r\n", otherwise just increment
    if (p[0] == '\r' && p[1] == '\n')
        p += 2;
    else
        p++;

    return p;
}

static wchar_t *csvFieldData(const wchar_t *fld_s, const wchar_t *fld_e, wchar_t *buffer, size_t buflen)
{
    wchar_t *dst = buffer;
    wchar_t *end = buffer + buflen - 1;
    const wchar_t *src = fld_s;

    if (*src == L'"')
    {
        const wchar_t *p = src + 1;
        while (p < fld_e && dst < end)
        {
            if (p[0] == L'"' && p+1 < fld_s && p[1] == L'"')
            {
                *dst++ = p[0];
                p += 2;
            }
            else if (p[0] == L'"')
            {
                p++;
                break;
            }
            else
                *dst++ = *p++;
        }
        src = p;
    }
    while (src < fld_e && dst < end)
        *dst++ = *src++;
    if (dst >= end)
        return 0;
    *dst = L'\0';
    return(buffer);
}

static void dissect(const wchar_t *line)
{
    const wchar_t *start = line;
    const wchar_t *next;
    bool     eol;
    wprintf(L"Input %3zd: [%.*ls]\n", wcslen(line), wcslen(line)-1, line);
    while ((next = nextCsvField(start, L',', &eol)) != 0)
    {
        wchar_t buffer[1024];
        wprintf(L"Raw Field: [%.*ls] (eol = %d)\n", (next - start - eol), start, eol);
        if (csvFieldData(start, next-1, buffer, sizeof(buffer)/sizeof(buffer[0])) != 0)
            wprintf(L"Field %3zd: [%ls]\n", wcslen(buffer), buffer);
        start = next;
    }
}

static const wchar_t multiline[] =
   L"First field of first row,\"This field is multiline\n"
    "\n"
    "but that's OK because it's enclosed in double quotes, and this\n"
    "is an escaped \"\" double quote\" but this one \"\" is not\n"
    "   \"This is second field of second row, but it is not multiline\n"
    "   because it doesn't start \n"
    "   with an immediate double quote\"\n"
    ;

int main(void)
{
    wchar_t line[1024];

    while (fgetws(line, sizeof(line)/sizeof(line[0]), stdin))
        dissect(line);
    dissect(multiline);

    return 0;
}

3

CSV ফাইলগুলি পার্স করার জন্য আমার একটি সহজেই ব্যবহারযোগ্য সি ++ লাইব্রেরি দরকার ছিল তবে কোনও পাওয়া যায়নি, তাই আমি একটি বিল্ডিং শেষ করেছি। র‌্যাপিডিসিভি হ'ল একটি সি ++ 11 শিরোলেখ-কেবল গ্রন্থাগার যা পছন্দের ডেটাটাইপগুলিতে ভেক্টর হিসাবে পার্সড কলামগুলি (বা সারিগুলি) থেকে সরাসরি অ্যাক্সেস দেয়। উদাহরণ স্বরূপ:

#include <iostream>
#include <vector>
#include <rapidcsv.h>

int main()
{
  rapidcsv::Document doc("../tests/msft.csv");

  std::vector<float> close = doc.GetColumn<float>("Close");
  std::cout << "Read " << close.size() << " values." << std::endl;
}

1
দুর্দান্ত কাজ, তবে শিরোনাম খালি লেবেল থাকলে লাইব্রেরিটি সঠিকভাবে কাজ করে না। এটি এক্সেল / লিব্রেঅফিস এনএক্সএন টেবিলের জন্য সাধারণ। এছাড়াও, এটি ডেটা শেষ লাইন এড়িয়ে যেতে পারে। দুর্ভাগ্যক্রমে, আপনার lib মজবুত নয়।
ম্যাকসিম গ্যানেনকো

1
@ ম্যাক্সেমগ্যানেনকো ফিডব্যাকের জন্য ধন্যবাদ আমি চূড়ান্ত লাইনের জন্য ডাব্লু / ও ট্রেলিং লাইন ব্রেকের জন্য "ডেটার শেষ লাইন" বাগ ঠিক করেছি। উল্লিখিত অন্যান্য সমস্যা হিসাবে - "খালি লেবেলযুক্ত শিরোনাম" - আমি নিশ্চিত না যে এটি কী বোঝায়? লাইব্রেরিতে খালি লেবেলগুলি হ্যান্ডেল করা উচিত (উদ্ধৃত এবং অ-উদ্ধৃত উভয়)। এটি শিরোনাম সারি / কলাম ব্যতীত সিএসভিও পড়তে পারে তবে তারপরে ব্যবহারকারীকে এটি নির্দিষ্ট করতে হবে (কল শিরোনাম আইডি -1 এবং সারি শিরোনাম আইডি -1)। দয়া করে কিছু বিশদ বিবরণ দিন বা গিটহাব পৃষ্ঠায় একটি বাগ রিপোর্ট করুন যদি আপনার কিছু নির্দিষ্ট ব্যবহারের ক্ষেত্রে সমর্থিত দেখতে চান। ধন্যবাদ!
d99kris

2

মাফ করবেন, তবে কোডগুলি কয়েকটি লাইনের আড়াল করার জন্য এগুলি সমস্ত বিস্তৃত সিনট্যাক্সের মতো দুর্দান্ত মনে হচ্ছে।

কেন এটি না:

/**

  Read line from a CSV file

  @param[in] fp file pointer to open file
  @param[in] vls reference to vector of strings to hold next line

  */
void readCSV( FILE *fp, std::vector<std::string>& vls )
{
    vls.clear();
    if( ! fp )
        return;
    char buf[10000];
    if( ! fgets( buf,999,fp) )
        return;
    std::string s = buf;
    int p,q;
    q = -1;
    // loop over columns
    while( 1 ) {
        p = q;
        q = s.find_first_of(",\n",p+1);
        if( q == -1 ) 
            break;
        vls.push_back( s.substr(p+1,q-p-1) );
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    std::vector<std::string> vls;
    FILE * fp = fopen( argv[1], "r" );
    if( ! fp )
        return 1;
    readCSV( fp, vls );
    readCSV( fp, vls );
    readCSV( fp, vls );
    std::cout << "row 3, col 4 is " << vls[3].c_str() << "\n";

    return 0;
}

আর্ম, সেখানে ",\n"স্ট্রিং থাকবে কেন ?
টিম্ম্ম্ম

@ টিম্মম স্ট্রিং ক্লাসের সাবস্ট্রটার পদ্ধতিটি সন্ধান করে এবং আপনি দেখতে পাবেন যে এটি একাধিক অক্ষর গ্রহণ করে, line n এটি নতুন লাইন চরিত্র, সুতরাং এটি একটি একক অক্ষর হিসাবে গণনা করা হয় instance এটি সামগ্রিকভাবে পুরো মানটির সন্ধান করে না। এটি প্রতিটি স্বতন্ত্র চরিত্রের জন্য অনুসন্ধান করছে; যথা কমা বা নিউলাইন। সাবস্ট্রাস্ট এটি প্রথম অক্ষরের সন্ধান করে এবং এটি -1 না পাওয়া গেলে তার অবস্থানটি ফিরিয়ে দেবে, যার অর্থ লাইনটি পড়া শেষ হয়েছে। এফপি ফাইলের অভ্যন্তরীণ অবস্থানের উপর নজর রাখে, তাই রিডিসিএসভিতে প্রতিটি কল এটি একবারে এক সারি সরিয়ে দেয়।
মার্টিন শট

2

এখানে ম্যাট্রিক্স পড়ার জন্য কোড দেওয়া আছে, নোট করুন ম্যাটল্যাবে আপনার সিএসভিরাইট ফাংশন রয়েছে

void loadFromCSV( const std::string& filename )
{
    std::ifstream       file( filename.c_str() );
    std::vector< std::vector<std::string> >   matrix;
    std::vector<std::string>   row;
    std::string                line;
    std::string                cell;

    while( file )
    {
        std::getline(file,line);
        std::stringstream lineStream(line);
        row.clear();

        while( std::getline( lineStream, cell, ',' ) )
            row.push_back( cell );

        if( !row.empty() )
            matrix.push_back( row );
    }

    for( int i=0; i<int(matrix.size()); i++ )
    {
        for( int j=0; j<int(matrix[i].size()); j++ )
            std::cout << matrix[i][j] << " ";

        std::cout << std::endl;
    }
}

2

আপনি fopen, fscanf ফাংশন ব্যবহার করে .csv ফাইলটি খুলতে এবং পড়তে পারেন তবে গুরুত্বপূর্ণ বিষয়টি হ'ল ডেটা পার্স করা del

মনে করুন আপনার ডেটা 1 সিএসভি ফাইলটি নিম্নরূপ:

A,45,76,01
B,77,67,02
C,63,76,03
D,65,44,04

আপনি ডেটা টোকানাইজ করতে এবং চর অ্যারেতে সঞ্চয় করতে পারেন এবং পরে যথাযথ রূপান্তরগুলির জন্য আটাই () ইত্যাদি ফাংশন ব্যবহার করতে পারেন

FILE *fp;
char str1[10], str2[10], str3[10], str4[10];

fp = fopen("G:\\data1.csv", "r");
if(NULL == fp)
{
    printf("\nError in opening file.");
    return 0;
}
while(EOF != fscanf(fp, " %[^,], %[^,], %[^,], %s, %s, %s, %s ", str1, str2, str3, str4))
{
    printf("\n%s %s %s %s", str1, str2, str3, str4);
}
fclose(fp);

[^,], it -ইট ইনভার্ট যুক্তি, এর অর্থ এমন কোনও স্ট্রিংয়ের সাথে মেলে যা শেষ পর্যন্ত কমা থাকে না, পূর্ববর্তী স্ট্রিংটি সমাপ্ত কমা দিয়ে মেলে বলে।


2

আপনাকে প্রথমে যে কাজটি করতে হবে তা হ'ল ফাইলটি বিদ্যমান কিনা তা নিশ্চিত করা। এটি সম্পাদন করার জন্য আপনাকে কেবল ফাইল স্ট্রিমটি চেষ্টা করে ওপেন করতে হবে। আপনি ফাইল স্ট্রিমটি খোলার পরে এটি প্রত্যাশার মতো কাজ করেছে কিনা তা দেখার জন্য স্ট্রিম.ফয়েল () ব্যবহার করুন।

bool fileExists(string fileName)
{

ifstream test;

test.open(fileName.c_str());

if (test.fail())
{
    test.close();
    return false;
}
else
{
    test.close();
    return true;
}
}

আপনাকে অবশ্যই যাচাই করতে হবে যে প্রদত্ত ফাইলটি সঠিক ধরণের ফাইল। এটি সম্পাদন করতে আপনাকে ফাইল এক্সটেনশান না পাওয়া পর্যন্ত প্রদত্ত ফাইল পথটি সন্ধান করতে হবে। আপনার কাছে একবার ফাইল এক্সটেনশানটি নিশ্চিত হয়ে নিন যে এটি একটি .csv ফাইল।

bool verifyExtension(string filename)
{
int period = 0;

for (unsigned int i = 0; i < filename.length(); i++)
{
    if (filename[i] == '.')
        period = i;
}

string extension;

for (unsigned int i = period; i < filename.length(); i++)
    extension += filename[i];

if (extension == ".csv")
    return true;
else
    return false;
}

এই ফাংশনটি ফাইলের এক্সটেনশানটি ফিরিয়ে দেবে যা পরে ত্রুটি বার্তায় ব্যবহৃত হয়।

string getExtension(string filename)
{
int period = 0;

for (unsigned int i = 0; i < filename.length(); i++)
{
    if (filename[i] == '.')
        period = i;
}

string extension;

if (period != 0)
{
    for (unsigned int i = period; i < filename.length(); i++)
        extension += filename[i];
}
else
    extension = "NO FILE";

return extension;
}

এই ফাংশনটি আসলে উপরে তৈরি ত্রুটি চেকগুলিকে কল করবে এবং তারপরে ফাইলটির মাধ্যমে বিশ্লেষণ করবে।

void parseFile(string fileName)
{
    if (fileExists(fileName) && verifyExtension(fileName))
    {
        ifstream fs;
        fs.open(fileName.c_str());
        string fileCommand;

        while (fs.good())
        {
            string temp;

            getline(fs, fileCommand, '\n');

            for (unsigned int i = 0; i < fileCommand.length(); i++)
            {
                if (fileCommand[i] != ',')
                    temp += fileCommand[i];
                else
                    temp += " ";
            }

            if (temp != "\0")
            {
                // Place your code here to run the file.
            }
        }
        fs.close();
    }
    else if (!fileExists(fileName))
    {
        cout << "Error: The provided file does not exist: " << fileName << endl;

        if (!verifyExtension(fileName))
        {
            if (getExtension(fileName) != "NO FILE")
                cout << "\tCheck the file extension." << endl;
            else
                cout << "\tThere is no file in the provided path." << endl;
        }
    }
    else if (!verifyExtension(fileName)) 
    {
        if (getExtension(fileName) != "NO FILE")
            cout << "Incorrect file extension provided: " << getExtension(fileName) << endl;
        else
            cout << "There is no file in the following path: " << fileName << endl;
    }
}

2

আপনি এত সুন্দর কিছু ব্যবহার করার সময় আপনাকে গর্বিত বোধ করতে হবে boost::spirit

এখানে আমার পার্সারের চেষ্টা (প্রায়) এই লিঙ্কের সিএসভি স্পেসিফিকেশনগুলির সাথে সম্মতি জানায় (আমার ক্ষেত্রের মধ্যে লাইন ব্রেকের দরকার নেই Also এছাড়াও কমাগুলির চারপাশের স্পেসগুলি বরখাস্ত করা হয়েছে)।

এই কোডটি সংকলনের জন্য 10 সেকেন্ড অপেক্ষা করার চমকপ্রদ অভিজ্ঞতাটি কাটিয়ে ওঠার পরে: আপনি পিছনে বসে উপভোগ করতে পারবেন।

// csvparser.cpp
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

#include <iostream>
#include <string>

namespace qi = boost::spirit::qi;
namespace bascii = boost::spirit::ascii;

template <typename Iterator>
struct csv_parser : qi::grammar<Iterator, std::vector<std::string>(), 
    bascii::space_type>
{
    qi::rule<Iterator, char()                                           > COMMA;
    qi::rule<Iterator, char()                                           > DDQUOTE;
    qi::rule<Iterator, std::string(),               bascii::space_type  > non_escaped;
    qi::rule<Iterator, std::string(),               bascii::space_type  > escaped;
    qi::rule<Iterator, std::string(),               bascii::space_type  > field;
    qi::rule<Iterator, std::vector<std::string>(),  bascii::space_type  > start;

    csv_parser() : csv_parser::base_type(start)
    {
        using namespace qi;
        using qi::lit;
        using qi::lexeme;
        using bascii::char_;

        start       = field % ',';
        field       = escaped | non_escaped;
        escaped     = lexeme['"' >> *( char_ -(char_('"') | ',') | COMMA | DDQUOTE)  >> '"'];
        non_escaped = lexeme[       *( char_ -(char_('"') | ',')                  )        ];
        DDQUOTE     = lit("\"\"")       [_val = '"'];
        COMMA       = lit(",")          [_val = ','];
    }

};

int main()
{
    std::cout << "Enter CSV lines [empty] to quit\n";

    using bascii::space;
    typedef std::string::const_iterator iterator_type;
    typedef csv_parser<iterator_type> csv_parser;

    csv_parser grammar;
    std::string str;
    int fid;
    while (getline(std::cin, str))
    {
        fid = 0;

        if (str.empty())
            break;

        std::vector<std::string> csv;
        std::string::const_iterator it_beg = str.begin();
        std::string::const_iterator it_end = str.end();
        bool r = phrase_parse(it_beg, it_end, grammar, space, csv);

        if (r && it_beg == it_end)
        {
            std::cout << "Parsing succeeded\n";
            for (auto& field: csv)
            {
                std::cout << "field " << ++fid << ": " << field << std::endl;
            }
        }
        else
        {
            std::cout << "Parsing failed\n";
        }
    }

    return 0;
}

কম্পাইল:

make csvparser

পরীক্ষা ( উইকিপিডিয়া থেকে চুরি উদাহরণ ):

./csvparser
Enter CSV lines [empty] to quit

1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00
Parsing succeeded
field 1: 1999
field 2: Chevy
field 3: Venture "Extended Edition, Very Large"
field 4: 
field 5: 5000.00

1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00"
Parsing failed

2

এই সমাধান এই 4 টি মামলা সনাক্ত করে

সম্পূর্ণ ক্লাস হয়

https://github.com/pedro-vicente/csv-parser

1,field 2,field 3,
1,field 2,"field 3 quoted, with separator",
1,field 2,"field 3
with newline",
1,field 2,"field 3
with newline and separator,",

এটি অক্ষর অনুসারে ফাইলের অক্ষরটি পড়ে এবং একবারে 1 সারি ভেক্টরের কাছে পড়ে (স্ট্রিংগুলির), তাই খুব বড় ফাইলগুলির জন্য উপযুক্ত।

ব্যবহার হয়

একটি খালি সারি ফিরে না আসা পর্যন্ত ফাইলের শেষ (ফাইলের শেষে)। একটি সারি একটি ভেক্টর যেখানে প্রতিটি এন্ট্রি একটি সিএসভি কলাম।

read_csv_t csv;
csv.open("../test.csv");
std::vector<std::string> row;
while (true)
{
  row = csv.read_row();
  if (row.size() == 0)
  {
    break;
  }
}

শ্রেণীর ঘোষণা

class read_csv_t
{
public:
  read_csv_t();
  int open(const std::string &file_name);
  std::vector<std::string> read_row();
private:
  std::ifstream m_ifs;
};

রুপায়ণ

std::vector<std::string> read_csv_t::read_row()
{
  bool quote_mode = false;
  std::vector<std::string> row;
  std::string column;
  char c;
  while (m_ifs.get(c))
  {
    switch (c)
    {
      /////////////////////////////////////////////////////////////////////////////////////////////////////
      //separator ',' detected. 
      //in quote mode add character to column
      //push column if not in quote mode
      /////////////////////////////////////////////////////////////////////////////////////////////////////

    case ',':
      if (quote_mode == true)
      {
        column += c;
      }
      else
      {
        row.push_back(column);
        column.clear();
      }
      break;

      /////////////////////////////////////////////////////////////////////////////////////////////////////
      //quote '"' detected. 
      //toggle quote mode
      /////////////////////////////////////////////////////////////////////////////////////////////////////

    case '"':
      quote_mode = !quote_mode;
      break;

      /////////////////////////////////////////////////////////////////////////////////////////////////////
      //line end detected
      //in quote mode add character to column
      //return row if not in quote mode
      /////////////////////////////////////////////////////////////////////////////////////////////////////

    case '\n':
    case '\r':
      if (quote_mode == true)
      {
        column += c;
      }
      else
      {
        return row;
      }
      break;

      /////////////////////////////////////////////////////////////////////////////////////////////////////
      //default, add character to column
      /////////////////////////////////////////////////////////////////////////////////////////////////////

    default:
      column += c;
      break;
    }
  }

  //return empty vector if end of file detected 
  m_ifs.close();
  std::vector<std::string> v;
  return v;
}

1

আপনি Qtগ্রন্থাগারের ক্ষমতাগুলিও একবার দেখতে পারেন ।

এটিতে নিয়মিত এক্সপ্রেশন সমর্থন রয়েছে এবং কিউ স্ট্রিং ক্লাসে দুর্দান্ত পদ্ধতি রয়েছে, যেমন split()কিউ স্ট্রিংলিস্ট ফিরিয়ে দেওয়া, সরবরাহিত ডিলিমিটার দিয়ে মূল স্ট্রিংকে বিভক্ত করে প্রাপ্ত স্ট্রিংগুলির তালিকা। সিএসভি ফাইলের জন্য যথেষ্ট হওয়া উচিত ..

প্রদত্ত শিরোনামের নাম সহ কলাম পেতে আমি নিম্নলিখিতগুলি ব্যবহার করি: c ++ উত্তরাধিকার Qt সমস্যা qstring



1

আপনি যদি আপনার প্রকল্পের উন্নয়নে অন্তর্ভুক্ত না করতে চান তবে (এটি যথেষ্ট বড় যদি আপনি এটির জন্য যা ব্যবহার করছেন সেটি হচ্ছে CSV পার্সিং ...)

আমি এখানে সিএসভি পার্সিংয়ের সাথে ভাগ্য পেয়েছি:

http://www.zedwood.com/article/112/cpp-csv-parser

এটি উদ্ধৃত ক্ষেত্রগুলি পরিচালনা করে - তবে ইনলাইন characters n অক্ষরগুলি হ্যান্ডেল করে না (যা সম্ভবত বেশিরভাগ ব্যবহারের জন্য ভাল)।


1
কম্পাইলারটি অপ্রয়োজনীয় সমস্ত কিছু বের করে ফেলা উচিত নয়?
তোফুটিম

1

এটি একটি পুরাতন থ্রেড তবে এটি এখনও অনুসন্ধানের ফলাফলের শীর্ষে রয়েছে, সুতরাং আমি আমার সমাধানটি std :: স্ট্রিংস্ট্রিম এবং একটি সহজ স্ট্রিং প্রতিস্থাপনের পদ্ধতিটি য্বেস বাউমস দ্বারা পেয়েছি যা আমি এখানে পেয়েছি adding

নিম্নলিখিত উদাহরণটি লাইন দ্বারা একটি ফাইল লাইন পড়বে, // দিয়ে শুরু হওয়া মন্তব্য লাইনগুলি উপেক্ষা করবে এবং স্ট্রিং, ইনটস এবং ডাবলসের সংমিশ্রণে অন্যান্য লাইনগুলি পার্স করবে। স্ট্রিং স্ট্রিম পার্সিং করে, তবে ক্ষেত্রগুলি হোয়াইটস্পেসের মাধ্যমে সীমাবদ্ধ করা প্রত্যাশা করে, তাই আমি কমাগুলিকে প্রথমে স্পেসে পরিণত করতে স্ট্রিংপ্লেস ব্যবহার করি। এটি ঠিক আছে ট্যাবগুলি পরিচালনা করে তবে উদ্ধৃত স্ট্রিংগুলির সাথে ডিল করে না।

খারাপ বা অনুপস্থিত ইনপুটটি সহজভাবে উপেক্ষা করা হবে, যা আপনার পরিস্থিতিতে নির্ভর করে ভাল বা নাও হতে পারে।

#include <string>
#include <sstream>
#include <fstream>

void StringReplace(std::string& str, const std::string& oldStr, const std::string& newStr)
// code by  Yves Baumes
// http://stackoverflow.com/questions/1494399/how-do-i-search-find-and-replace-in-a-standard-string
{
  size_t pos = 0;
  while((pos = str.find(oldStr, pos)) != std::string::npos)
  {
     str.replace(pos, oldStr.length(), newStr);
     pos += newStr.length();
  }
}

void LoadCSV(std::string &filename) {
   std::ifstream stream(filename);
   std::string in_line;
   std::string Field;
   std::string Chan;
   int ChanType;
   double Scale;
   int Import;
   while (std::getline(stream, in_line)) {
      StringReplace(in_line, ",", " ");
      std::stringstream line(in_line);
      line >> Field >> Chan >> ChanType >> Scale >> Import;
      if (Field.substr(0,2)!="//") {
         // do your stuff 
         // this is CBuilder code for demonstration, sorry
         ShowMessage((String)Field.c_str() + "\n" + Chan.c_str() + "\n" + IntToStr(ChanType) + "\n" +FloatToStr(Scale) + "\n" +IntToStr(Import));
      }
   }
}

1

এটি মূল্যবান জন্য, আমার বাস্তবায়ন এখানে। এটি স্ট্রিং ইনপুট নিয়ে কাজ করে তবে সহজেই স্ট্রিংয়ের সাথে সামঞ্জস্য করা যায়। এটি ক্ষেত্রগুলিতে নিউলাইন হ্যান্ডেল করে না (কারণ আমার অ্যাপ্লিকেশনটি হয় না তবে এর সমর্থন যোগ করা খুব কঠিন নয়) এবং এটি আরএফসি অনুসারে "\ r \ n" লাইনের শেষের সাথে সম্মতি দেয় না (ধরে নিচ্ছেন যে আপনি std :: getline), তবে এটি হোয়াইটস্পেস ট্রিমিং এবং ডাবল-কোটগুলি সঠিকভাবে পরিচালনা করবে (আশা করি)।

using namespace std;

// trim whitespaces around field or double-quotes, remove double-quotes and replace escaped double-quotes (double double-quotes)
wstring trimquote(const wstring& str, const wstring& whitespace, const wchar_t quotChar)
{
    wstring ws;
    wstring::size_type strBegin = str.find_first_not_of(whitespace);
    if (strBegin == wstring::npos)
        return L"";

    wstring::size_type strEnd = str.find_last_not_of(whitespace);
    wstring::size_type strRange = strEnd - strBegin + 1;

    if((str[strBegin] == quotChar) && (str[strEnd] == quotChar))
    {
        ws = str.substr(strBegin+1, strRange-2);
        strBegin = 0;
        while((strEnd = ws.find(quotChar, strBegin)) != wstring::npos)
        {
            ws.erase(strEnd, 1);
            strBegin = strEnd+1;
        }

    }
    else
        ws = str.substr(strBegin, strRange);
    return ws;
}

pair<unsigned, unsigned> nextCSVQuotePair(const wstring& line, const wchar_t quotChar, unsigned ofs = 0)
{
    pair<unsigned, unsigned> r;
    r.first = line.find(quotChar, ofs);
    r.second = wstring::npos;
    if(r.first != wstring::npos)
    {
        r.second = r.first;
        while(((r.second = line.find(quotChar, r.second+1)) != wstring::npos)
            && (line[r.second+1] == quotChar)) // WARNING: assumes null-terminated string such that line[r.second+1] always exist
            r.second++;

    }
    return r;
}

unsigned parseLine(vector<wstring>& fields, const wstring& line)
{
    unsigned ofs, ofs0, np;
    const wchar_t delim = L',';
    const wstring whitespace = L" \t\xa0\x3000\x2000\x2001\x2002\x2003\x2004\x2005\x2006\x2007\x2008\x2009\x200a\x202f\x205f";
    const wchar_t quotChar = L'\"';
    pair<unsigned, unsigned> quot;

    fields.clear();

    ofs = ofs0 = 0;
    quot = nextCSVQuotePair(line, quotChar);
    while((np = line.find(delim, ofs)) != wstring::npos)
    {
        if((np > quot.first) && (np < quot.second))
        { // skip delimiter inside quoted field
            ofs = quot.second+1;
            quot = nextCSVQuotePair(line, quotChar, ofs);
            continue;
        }
        fields.push_back( trimquote(line.substr(ofs0, np-ofs0), whitespace, quotChar) );
        ofs = ofs0 = np+1;
    }
    fields.push_back( trimquote(line.substr(ofs0), whitespace, quotChar) );

    return fields.size();
}

1

আপনার প্রয়োজনীয় সমস্তটি যদি ডাবলসের কোনও ডেটা ফাইল (কোনও পূর্ণসংখ্যা নয়, কোনও পাঠ্য নেই) লোড করা হয় তবে এখানে প্রস্তুত-প্রস্তুত ফাংশন রয়েছে।

#include <sstream>
#include <fstream>
#include <iterator>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

/**
 * Parse a CSV data file and fill the 2d STL vector "data".
 * Limits: only "pure datas" of doubles, not encapsulated by " and without \n inside.
 * Further no formatting in the data (e.g. scientific notation)
 * It however handles both dots and commas as decimal separators and removes thousand separator.
 * 
 * returnCodes[0]: file access 0-> ok 1-> not able to read; 2-> decimal separator equal to comma separator
 * returnCodes[1]: number of records
 * returnCodes[2]: number of fields. -1 If rows have different field size
 * 
 */
vector<int>
readCsvData (vector <vector <double>>& data, const string& filename, const string& delimiter, const string& decseparator){

 int vv[3] = { 0,0,0 };
 vector<int> returnCodes(&vv[0], &vv[0]+3);

 string rowstring, stringtoken;
 double doubletoken;
 int rowcount=0;
 int fieldcount=0;
 data.clear();

 ifstream iFile(filename, ios_base::in);
 if (!iFile.is_open()){
   returnCodes[0] = 1;
   return returnCodes;
 }
 while (getline(iFile, rowstring)) {
    if (rowstring=="") continue; // empty line
    rowcount ++; //let's start with 1
    if(delimiter == decseparator){
      returnCodes[0] = 2;
      return returnCodes;
    }
    if(decseparator != "."){
     // remove dots (used as thousand separators)
     string::iterator end_pos = remove(rowstring.begin(), rowstring.end(), '.');
     rowstring.erase(end_pos, rowstring.end());
     // replace decimal separator with dots.
     replace(rowstring.begin(), rowstring.end(),decseparator.c_str()[0], '.'); 
    } else {
     // remove commas (used as thousand separators)
     string::iterator end_pos = remove(rowstring.begin(), rowstring.end(), ',');
     rowstring.erase(end_pos, rowstring.end());
    }
    // tokenize..
    vector<double> tokens;
    // Skip delimiters at beginning.
    string::size_type lastPos = rowstring.find_first_not_of(delimiter, 0);
    // Find first "non-delimiter".
    string::size_type pos     = rowstring.find_first_of(delimiter, lastPos);
    while (string::npos != pos || string::npos != lastPos){
        // Found a token, convert it to double add it to the vector.
        stringtoken = rowstring.substr(lastPos, pos - lastPos);
        if (stringtoken == "") {
      tokens.push_back(0.0);
    } else {
          istringstream totalSString(stringtoken);
      totalSString >> doubletoken;
      tokens.push_back(doubletoken);
    }     
        // Skip delimiters.  Note the "not_of"
        lastPos = rowstring.find_first_not_of(delimiter, pos);
        // Find next "non-delimiter"
        pos = rowstring.find_first_of(delimiter, lastPos);
    }
    if(rowcount == 1){
      fieldcount = tokens.size();
      returnCodes[2] = tokens.size();
    } else {
      if ( tokens.size() != fieldcount){
    returnCodes[2] = -1;
      }
    }
    data.push_back(tokens);
 }
 iFile.close();
 returnCodes[1] = rowcount;
 return returnCodes;
}

1

আর একটি দ্রুত এবং সহজ উপায় হ'ল Boost.Fusion I/O:

#include <iostream>
#include <sstream>

#include <boost/fusion/adapted/boost_tuple.hpp>
#include <boost/fusion/sequence/io.hpp>

namespace fusion = boost::fusion;

struct CsvString
{
    std::string value;

    // Stop reading a string once a CSV delimeter is encountered.
    friend std::istream& operator>>(std::istream& s, CsvString& v) {
        v.value.clear();
        for(;;) {
            auto c = s.peek();
            if(std::istream::traits_type::eof() == c || ',' == c || '\n' == c)
                break;
            v.value.push_back(c);
            s.get();
        }
        return s;
    }

    friend std::ostream& operator<<(std::ostream& s, CsvString const& v) {
        return s << v.value;
    }
};

int main() {
    std::stringstream input("abc,123,true,3.14\n"
                            "def,456,false,2.718\n");

    typedef boost::tuple<CsvString, int, bool, double> CsvRow;

    using fusion::operator<<;
    std::cout << std::boolalpha;

    using fusion::operator>>;
    input >> std::boolalpha;
    input >> fusion::tuple_open("") >> fusion::tuple_close("\n") >> fusion::tuple_delimiter(',');

    for(CsvRow row; input >> row;)
        std::cout << row << '\n';
}

আউটপুট:

(abc 123 true 3.14)
(def 456 false 2.718)

1

আমি সিএসভি ফাইলগুলি পার্স করার একটি দুর্দান্ত উপায় লিখেছিলাম এবং আমি ভেবেছিলাম এটি উত্তর হিসাবে যুক্ত করা উচিত:

#include <algorithm>
#include <fstream>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>

struct CSVDict
{
  std::vector< std::string > inputImages;
  std::vector< double > inputLabels;
};

/**
\brief Splits the string

\param str String to split
\param delim Delimiter on the basis of which splitting is to be done
\return results Output in the form of vector of strings
*/
std::vector<std::string> stringSplit( const std::string &str, const std::string &delim )
{
  std::vector<std::string> results;

  for (size_t i = 0; i < str.length(); i++)
  {
    std::string tempString = "";
    while ((str[i] != *delim.c_str()) && (i < str.length()))
    {
      tempString += str[i];
      i++;
    }
    results.push_back(tempString);
  }

  return results;
}

/**
\brief Parse the supplied CSV File and obtain Row and Column information. 

Assumptions:
1. Header information is in first row
2. Delimiters are only used to differentiate cell members

\param csvFileName The full path of the file to parse
\param inputColumns The string of input columns which contain the data to be used for further processing
\param inputLabels The string of input labels based on which further processing is to be done
\param delim The delimiters used in inputColumns and inputLabels
\return Vector of Vector of strings: Collection of rows and columns
*/
std::vector< CSVDict > parseCSVFile( const std::string &csvFileName, const std::string &inputColumns, const std::string &inputLabels, const std::string &delim )
{
  std::vector< CSVDict > return_CSVDict;
  std::vector< std::string > inputColumnsVec = stringSplit(inputColumns, delim), inputLabelsVec = stringSplit(inputLabels, delim);
  std::vector< std::vector< std::string > > returnVector;
  std::ifstream inFile(csvFileName.c_str());
  int row = 0;
  std::vector< size_t > inputColumnIndeces, inputLabelIndeces;
  for (std::string line; std::getline(inFile, line, '\n');)
  {
    CSVDict tempDict;
    std::vector< std::string > rowVec;
    line.erase(std::remove(line.begin(), line.end(), '"'), line.end());
    rowVec = stringSplit(line, delim);

    // for the first row, record the indeces of the inputColumns and inputLabels
    if (row == 0)
    {
      for (size_t i = 0; i < rowVec.size(); i++)
      {
        for (size_t j = 0; j < inputColumnsVec.size(); j++)
        {
          if (rowVec[i] == inputColumnsVec[j])
          {
            inputColumnIndeces.push_back(i);
          }
        }
        for (size_t j = 0; j < inputLabelsVec.size(); j++)
        {
          if (rowVec[i] == inputLabelsVec[j])
          {
            inputLabelIndeces.push_back(i);
          }
        }
      }
    }
    else
    {
      for (size_t i = 0; i < inputColumnIndeces.size(); i++)
      {
        tempDict.inputImages.push_back(rowVec[inputColumnIndeces[i]]);
      }
      for (size_t i = 0; i < inputLabelIndeces.size(); i++)
      {
        double test = std::atof(rowVec[inputLabelIndeces[i]].c_str());
        tempDict.inputLabels.push_back(std::atof(rowVec[inputLabelIndeces[i]].c_str()));
      }
      return_CSVDict.push_back(tempDict);
    }
    row++;
  }

  return return_CSVDict;
}

1

এটি ব্যবহার করা সম্ভব std::regex

আপনার ফাইল এবং মেমরি আপনার জন্য উপলব্ধ আকারের উপর নির্ভর করে, এটা সম্ভব এটা লাইন দ্বারা বা সম্পূর্ণরূপে একটি ইন পারেন লাইন পঠিত std::string

করার ফাইলটি পড়ার এক ব্যবহার করতে পারেন:

std::ifstream t("file.txt");
std::string sin((std::istreambuf_iterator<char>(t)),
                 std::istreambuf_iterator<char>());

তারপরে আপনি এটির সাথে মিলতে পারেন যা আপনার প্রয়োজনের জন্য কাস্টমাইজযোগ্য।

std::regex word_regex(",\\s]+");
auto what = 
    std::sregex_iterator(sin.begin(), sin.end(), word_regex);
auto wend = std::sregex_iterator();

std::vector<std::string> v;
for (;what!=wend ; wend) {
    std::smatch match = *what;
    v.push_back(match.str());
}

1

যেহেতু আমি এখনই বাড়াতে ব্যবহার করি না, তাই আমি আরও সহজ সমাধানের পরামর্শ দেব। ধরুন ধরুন যে আপনার .csv ফাইলে একটি ',' দ্বারা বিভক্ত প্রতিটি লাইনে 10 নম্বর সহ 100 টি লাইন রয়েছে। আপনি নিম্নলিখিত কোড সহ একটি অ্যারের আকারে এই ডেটাটি লোড করতে পারেন:

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
using namespace std;

int main()
{
    int A[100][10];
    ifstream ifs;
    ifs.open("name_of_file.csv");
    string s1;
    char c;
    for(int k=0; k<100; k++)
    {
        getline(ifs,s1);
        stringstream stream(s1);
        int j=0;
        while(1)
        {
            stream >>A[k][j];
            stream >> c;
            j++;
            if(!stream) {break;}
        }
    }


}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.