请注意,此代码在 boost v1.69 的spirit x3 上编译时没有错误,该代码最初是为此开发的。该错误源自 x3::parse() 行,但由于这个模板噪音,我不知道编译器实际上想告诉我什么,也不知道为什么spirit x3 1.84有这个错误,而1.69没有。 c++17 模式下的 g++ 13.2:
#include <boost/spirit/home/x3.hpp>
#include <algorithm>
#include <iomanip>
#include <iterator>
#include <stdexcept>
namespace x3 = boost::spirit::x3;
namespace {
using x3::char_;
using x3::lit;
using x3::no_skip;
const auto escaped =
lit('"') >> *((char_ - '"') | lit('"') >> char_('"')) >> lit('"');
const auto non_escaped =
*(char_ - (lit(',') | lit('"') | lit('\r') | lit('\n')));
const auto field = escaped | non_escaped;
const auto record = (field % ',') >> (lit("\r\n") | lit('\n') | !char_);
} //namespace
namespace utils {
std::vector<std::string> parse_csv(std::string_view input,
std::string_view& remainder)
{
std::vector<std::string> result;
auto first { std::begin(input) };
if (!x3::parse(first, std::end(input), record, result)) {
throw std::runtime_error{"CSV parse failure"};
}
remainder = input.substr(std::distance(std::begin(input), first));
return result;
}
}
在削减了我希望的许多行错误消息之后,这些错误消息并不突出:
/data3/jbuster/boost-build/install/xgcc/boost/1.84/include/boost/spirit/home/x3/support/traits/move_to.hpp:164:9: note: template argument deduction/substitution failed:
/data3/jbuster/boost-build/install/xgcc/boost/1.84/include/boost/spirit/home/x3/support/traits/move_to.hpp:196:24: note: deduced conflicting types for parameter ‘Iterator’ (‘char’ and ‘std::__cxx11::basic_string<char>’)
196 | detail::move_to(src, dest, typename attribute_category<Dest>::type());
| ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/data3/jbuster/boost-build/install/xgcc/boost/1.84/include/boost/spirit/home/x3/support/traits/move_to.hpp:168:9: note: candidate: ‘template<class Iterator, class Dest> void boost::spirit::x3::traits::detail::move_to(Iterator, Iterator, Dest&, boost::spirit::x3::traits::container_attribute)’
168 | move_to(Iterator first, Iterator last, Dest& dest, container_attribute)
| ^~~~~~~
/data3/jbuster/boost-build/install/xgcc/boost/1.84/include/boost/spirit/home/x3/support/traits/move_to.hpp:168:9: note: template argument deduction/substitution failed:
/data3/jbuster/boost-build/install/xgcc/boost/1.84/include/boost/spirit/home/x3/support/traits/move_to.hpp:196:24: note: deduced conflicting types for parameter ‘Iterator’ (‘char’ and ‘std::__cxx11::basic_string<char>’)
196 | detail::move_to(src, dest, typename attribute_category<Dest>::type());
| ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/data3/jbuster/boost-build/install/xgcc/boost/1.84/include/boost/spirit/home/x3/support/traits/move_to.hpp:180:9: note: candidate: ‘template<class Iterator, class Dest> typename boost::enable_if<boost::spirit::x3::traits::is_size_one_sequence<Dest> >::type boost::spirit::x3::traits::detail::move_to(Iterator, Iterator, Dest&, boost::spirit::x3::traits::tuple_attribute)’
180 | move_to(Iterator first, Iterator last, Dest& dest, tuple_attribute)
| ^~~~~~~
/data3/jbuster/boost-build/install/xgcc/boost/1.84/include/boost/spirit/home/x3/support/traits/move_to.hpp:180:9: note: template argument deduction/substitution failed:
/data3/jbuster/boost-build/install/xgcc/boost/1.84/include/boost/spirit/home/x3/support/traits/move_to.hpp:196:24: note: deduced conflicting types for parameter ‘Iterator’ (‘char’ and ‘std::__cxx11::basic_string<char>’)
196 | detail::move_to(src, dest, typename attribute_category<Dest>::type());
| ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/data3/jbuster/boost-build/install/xgcc/boost/1.84/include/boost/spirit/home/x3/support/traits/move_to.hpp:187:9: note: candidate: ‘template<class Iterator> void boost::spirit::x3::traits::detail::move_to(Iterator, Iterator, boost::iterator_range<T>&, boost::spirit::x3::traits::range_attribute)’
187 | move_to(Iterator first, Iterator last, boost::iterator_range<Iterator>& rng, range_attribute)
| ^~~~~~~
/data3/jbuster/boost-build/install/xgcc/boost/1.84/include/boost/spirit/home/x3/support/traits/move_to.hpp:187:9: note: template argument deduction/substitution failed:
/data3/jbuster/boost-build/install/xgcc/boost/1.84/include/boost/spirit/home/x3/support/traits/move_to.hpp:196:24: note: deduced conflicting types for parameter ‘Iterator’ (‘char’ and ‘std::__cxx11::basic_string<char>’)
196 | detail::move_to(src, dest, typename attribute_category<Dest>::type());
| ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
X3的属性合成/兼容性规则一直在变化。在这个特定领域(字符串合成),我看到了一些改进,但也看到了“随机行为变化”。
这一切都很好,因为 X3 接口(仍然)被记录为“实验性”。
对属性合成有一点帮助,改变
auto const field = escaped | non_escaped;
到
auto const field = x3::rule<void, std::string> {} = escaped | non_escaped;
这是一个包含测试用例和许多简化/改进的演示:
住在科里鲁
#include <boost/spirit/home/x3.hpp>
namespace CsvParser {
namespace x3 = boost::spirit::x3;
auto const escaped = '"' >> *(~x3::char_('"') | '"' >> x3::char_('"')) >> '"';
auto const non_escaped = *~x3::char_(",\"\r\n");
auto const field = x3::rule<void, std::string> {} = escaped | non_escaped;
auto const record = (field % ',') >> (x3::eol | x3::eoi);
} // namespace
namespace utils {
std::vector<std::string> parse_csv_record(std::string_view input, std::string_view& remainder) {
std::vector<std::string> result;
if (auto f{std::begin(input)}; parse(f, std::end(input), CsvParser::record, result))
remainder = input.substr(std::distance(std::begin(input), f));
else
throw std::runtime_error{"CSV parse failure"};
return result;
}
} // namespace utils
#include <fmt/ranges.h>
int main() {
std::string_view demo = R"(
foo,bar,qux
1,"some, not all, things","are",created equal,
,,
,"
'multi'
""line"" baby"
)";
for (int lno = 1; !demo.empty(); ++lno) {
auto v = utils::parse_csv_record(demo, demo);
fmt::print("line #{}: {}\n", lno, v);
}
}
打印预期内容
line #1: [""]
line #2: ["foo", "bar", "qux"]
line #3: ["1", "some, not all, things", "are", "created equal", ""]
line #4: [""]
line #5: ["", "", ""]
line #6: ["", "\n'multi'\n\"line\" baby"]
一次解析整个文件:
namespace Csv {
using Record = std::vector<std::string>;
using File = std::vector<Record>;
File parse(std::string_view input) {
File result;
parse(std::begin(input), std::end(input), CsvParser::record % x3::eol > x3::eoi, result);
return result;
}
} // namespace Csv
印刷
parsed
-----
["foo", "bar", "qux"]
["1", "some, not all, things", "are", "created equal", ""]
[""]
["", "", ""]
["", "\n'multi'\n\"line\" baby"]
¹ 例如
raw[p] >> raw[p]
突然变得与 std::string
绑定属性引用兼容的情况;我不确定我是否同意