7

私はこのcsv行を持っています

std::string s = R"(1997,Ford,E350,"ac, abs, moon","some "rusty" parts",3000.00)";

次を使用して解析できますboost::tokenizer

typedef boost::tokenizer< boost::escaped_list_separator<char> , std::string::const_iterator, std::string> Tokenizer;
boost::escaped_list_separator<char> seps('\\', ',', '\"');
Tokenizer tok(s, seps);
for (auto i : tok)
{
    std::cout << i << std::endl;
}

トークン「rusty」に削除される二重引用符が必要であることを除いて、それは正しくなります。

これがboost::spiritを使用する私の試みです

boost::spirit::classic::rule<> list_csv_item = !(boost::spirit::classic::confix_p('\"', *boost::spirit::classic::c_escape_ch_p, '\"') | boost::spirit::classic::longest_d[boost::spirit::classic::real_p | boost::spirit::classic::int_p]);
std::vector<std::string> vec_item;
std::vector<std::string>  vec_list;
boost::spirit::classic::rule<> list_csv = boost::spirit::classic::list_p(list_csv_item[boost::spirit::classic::push_back_a(vec_item)],',')[boost::spirit::classic::push_back_a(vec_list)];
boost::spirit::classic::parse_info<> result = parse(s.c_str(), list_csv);
if (result.hit)
{
  for (auto i : vec_item)
  {
    cout << i << endl;
   }
}

問題:

  1. 機能せず、最初のトークンのみを出力します

  2. なぜブースト::スピリット::クラシック? Spirit V2 を使用した例が見つからない

  3. セットアップは残忍です..しかし、私はこれで暮らすことができます

boost::spirit**かなり速い傾向にあるのでどうしても使いたい

期待される出力:

1997
Ford
E350
ac, abs, moon
some "rusty" parts

3000.00

4

2 に答える 2

5

Sehe の投稿は私の投稿よりもかなりきれいに見えますが、私はこれを少しまとめていたので、とにかくここにあります。

#include <boost/tokenizer.hpp>
#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;

int main() {
    const std::string s = R"(1997,Ford,E350,"ac, abs, moon",""rusty"",3000.00)";

    // Tokenizer
    typedef boost::tokenizer< boost::escaped_list_separator<char> , std::string::const_iterator, std::string> Tokenizer;
    boost::escaped_list_separator<char> seps('\\', ',', '\"');
    Tokenizer tok(s, seps);
    for (auto i : tok)
        std::cout << i << "\n";
    std::cout << "\n";

    // Boost Spirit Qi
    qi::rule<std::string::const_iterator, std::string()> quoted_string = '"' >> *(qi::char_ - '"') >> '"';
    qi::rule<std::string::const_iterator, std::string()> valid_characters = qi::char_ - '"' - ',';
    qi::rule<std::string::const_iterator, std::string()> item = *(quoted_string | valid_characters );
    qi::rule<std::string::const_iterator, std::vector<std::string>()> csv_parser = item % ',';

    std::string::const_iterator s_begin = s.begin();
    std::string::const_iterator s_end = s.end();
    std::vector<std::string> result;

    bool r = boost::spirit::qi::parse(s_begin, s_end, csv_parser, result);
    assert(r == true);
    assert(s_begin == s_end);

    for (auto i : result)
        std::cout << i << std::endl;
    std::cout << "\n";
}   

そして、これは以下を出力します:

1997
Ford
E350
ac, abs, moon
rusty
3000.00

1997
Ford
E350
ac, abs, moon
rusty
3000.00

注目すべき点: これは完全な CSV パーサーを実装していません。また、エスケープ文字など、実装に必要なものを調べたいと思うでしょう。

また、ドキュメントを調べている場合は、ご存じのように、Qi では'a'と同等でboost::spirit::qi::lit('a')あり、"abc"と同等boost::spirit::qi::lit("abc")です。

二重引用符について: Sehe が上記のコメントで述べているよう""に、入力テキスト内の a を囲むルールが何を意味するのかは直接的には明確ではありません。""引用符で囲まれた文字列内にない のすべてのインスタンスを に変換したい場合は"、次のようなものが機能します。

qi::rule<std::string::const_iterator, std::string()> double_quote_char = "\"\"" >> qi::attr('"');
qi::rule<std::string::const_iterator, std::string()> item = *(double_quote_char | quoted_string | valid_characters );
于 2013-08-21T19:49:15.510 に答える