簡體   English   中英

C++ boost::qi 將空格和換行符分隔的數字解析為二維向量

[英]C++ boost::qi parse space and newline delimited numbers as a 2D vector

我有多個浮點數行,一行中的數字是空格分隔的,例如

1.2 2.2 3.2
1.1 2.1 3.1

我想將上述數字提取為字符串並解析為二維向量; std::vector< std::vector< std::string > > { {"1.2", "2.2", "3.2"},{"1.1", "2.1", "3.1} }

我的代碼如下所示。

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <string>

namespace client
{
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;

    using VecType = std::vector< std::vector< std::string >>; 
    
    struct employee
    {
        VecType name;
    };
}

BOOST_FUSION_ADAPT_STRUCT(
    client::employee,
    (client::VecType, name)
)
//]

namespace client
{
    template <typename Iterator>
    struct employee_parser : qi::grammar<Iterator, VecType(), ascii::space_type>
    {
        employee_parser() : employee_parser::base_type(start)
        {
            using qi::lexeme;
            using ascii::char_;

            number %= lexeme[+char_( "0-9." ) >>  qi::space ];
            start %= +number;
        }

        qi::rule<Iterator, std::string(), ascii::space_type> number;
        qi::rule<Iterator, VecType(), ascii::space_type> start;
    };
}

但這會產生 2D 向量,其外部向量大小為 6,每個內部向量大小為 1。

我不明白如何將字符串從新行中拆分為僅生成 2 個內部向量。

你必須拆分規則。 讓我們從類型開始:

using VecType = std::vector<std::string>;
using VecVecType = std::vector<VecType>;

現在,讓我們制定一個規則來解析一個數字、一行數字和多行:

qi::rule<Iterator, std::string()> number;
qi::rule<Iterator, VecType(), qi::blank_type> row;
qi::rule<Iterator, VecVecType()> start;

實現它們(請注意,我將船長移到了語法中,因為將其泄漏到接口中不是一個好主意):

number = raw [ double_ ]; // raw[] to get string value
row    = +number;
start  = qi::skip(blank) [ row % eol ];

注意:我使用blank而不是space ,因為我們不想跳過對語法很重要的eol

演示

住在科利魯

#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iomanip>

namespace client {
    namespace qi = boost::spirit::qi;

    using VecType = std::vector<std::string>;
    using VecVecType = std::vector<VecType>;
} // namespace client

namespace client {
    template <typename Iterator>
    struct my_parser : qi::grammar<Iterator, VecVecType()> {
        my_parser() : my_parser::base_type(start) {
            using namespace qi;

            number = raw [ double_ ]; // raw[] to get string value
            row    = *number;
            start  = qi::skip(blank) [ row % eol ];
        }

        qi::rule<Iterator, std::string()> number;
        qi::rule<Iterator, VecType(), qi::blank_type> row;
        qi::rule<Iterator, VecVecType()> start;
    };
} // namespace client

int main() {
    client::my_parser<std::string::const_iterator> const p;
    for (std::string const& input: {
            "",
            "1.2 2.2 3.2\n1.1 2.1 3.1",
            })
    {
        std::cout << "--- " << std::quoted(input) << " -----\n";
        auto f = begin(input), l = end(input);
        client::VecVecType output;
        if (parse(f, l, p, output)) {
            std::cout << "Parsed:\n";
            for (auto& row : output) {
                for (auto& v : row) {
                    std::cout << "\t" << v;
                }
                std::cout << "\n";
            }
        } else {
            std::cout << "Failed\n";
        }
        if (f!=l) {
            std::cout << "Remaining input: " << std::quoted(std::string(f,l)) << "\n";
        }
    }
}

印刷

--- "" -----
Parsed:

--- "1.2 2.2 3.2
1.1 2.1 3.1" -----
Parsed:
    1.2 2.2 3.2
    1.1 2.1 3.1

獎金

強類型化讓一切變得更有趣:如果可以解析成雙精度,為什么還要解析成字符串?

還展示了如何啟用規則調試:

住在科利魯

#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iomanip>

namespace client {
    namespace qi = boost::spirit::qi;

    using VecType = std::vector<double>;
    using VecVecType = std::vector<VecType>;
} // namespace client

namespace client {
    template <typename Iterator>
    struct my_parser : qi::grammar<Iterator, VecVecType()> {
        my_parser() : my_parser::base_type(start) {
            using namespace qi;

            row    = *double_;
            start  = qi::skip(blank) [ row % eol ];

            BOOST_SPIRIT_DEBUG_NODES((start)(row))
        }

      private:
        qi::rule<Iterator, VecType(), qi::blank_type> row;
        qi::rule<Iterator, VecVecType()> start;
    };
} // namespace client

int main() {
    client::my_parser<std::string::const_iterator> const p;
    for (std::string const& input: {
            "",
            "1.2 2.2 3.2\n1.1 2.1 3.1",
            })
    {
        std::cout << "--- " << std::quoted(input) << " -----\n";
        auto f = begin(input), l = end(input);
        client::VecVecType output;
        if (parse(f, l, p, output)) {
            std::cout << "Parsed:\n";
            for (auto& row : output) {
                for (auto& v : row) {
                    std::cout << "\t" << v;
                }
                std::cout << "\n";
            }
        } else {
            std::cout << "Failed\n";
        }
        if (f!=l) {
            std::cout << "Remaining input: " << std::quoted(std::string(f,l)) << "\n";
        }
    }
}

印刷

--- "" -----
<start>
  <try></try>
  <row>
    <try></try>
    <success></success>
    <attributes>[[]]</attributes>
  </row>
  <success></success>
  <attributes>[[[]]]</attributes>
</start>
Parsed:

--- "1.2 2.2 3.2
1.1 2.1 3.1" -----
<start>
  <try>1.2 2.2 3.2\n1.1 2.1 </try>
  <row>
    <try>1.2 2.2 3.2\n1.1 2.1 </try>
    <success>\n1.1 2.1 3.1</success>
    <attributes>[[1.2, 2.2, 3.2]]</attributes>
  </row>
  <row>
    <try>1.1 2.1 3.1</try>
    <success></success>
    <attributes>[[1.1, 2.1, 3.1]]</attributes>
  </row>
  <success></success>
  <attributes>[[[1.2, 2.2, 3.2], [1.1, 2.1, 3.1]]]</attributes>
</start>
Parsed:
    1.2 2.2 3.2
    1.1 2.1 3.1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM