为什么 Boost.Spirit x3 规则使用尖括号正确解析,但使用引号解析错误?
Why does this Boost.Spirit x3 rule parse correctly with angle brackets, but incorrectly with quotes?
下面的程序尝试解析 C++ header 包含字符串,例如 "my/file.hpp"
和 <my/file.hpp>
。由于我不明白的原因,我的代码无法解析 "
header。这是 Spirit 中的错误,还是我遗漏了一些明显的东西?
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <string>
#include <cassert>
using namespace boost::spirit::x3;
int main() {
auto header_name_brackets = '<' >> *(~char_('>')) >> '>';
auto header_name_quotes = '"' >> *(~char_('>')) >> '"';
{
auto s = std::string{"<my/file.hpp>"};
std::string parsed;
assert(phrase_parse(s.begin(), s.end(), header_name_brackets, space, parsed));
}
{
auto s = std::string{"\"my/file.hpp\""};
std::string parsed;
// this assert fails, but I don't know why.
assert(phrase_parse(s.begin(), s.end(), header_name_quotes, space, parsed));
}
}
您需要更改此规则:
auto header_name_quotes = '"' >> *(~char_('>')) >> '"';
至
auto header_name_quotes = '"' >> *(~char_('\"')) >> '"';
这对我有用:
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <string>
#include <cassert>
using namespace boost::spirit::x3;
int main() {
auto header_name_brackets = '<' >> *(~char_('>')) >> '>';
auto header_name_quotes = '"' >> *(~char_('"')) >> '"';
{
auto s = std::string{"<my/file.hpp>"};
std::string parsed;
assert(phrase_parse(s.begin(), s.end(), header_name_brackets, space, parsed));
}
{
auto s = std::string{"\"my/file.hpp\""};
std::string parsed;
// this assert fails, but I don't know why.
assert(phrase_parse(s.begin(), s.end(), header_name_quotes, space, parsed));
}
}
请注意,在第二种情况下,您需要匹配除 "
之外的所有字符,就像您在第一种情况下对 >
所做的那样。
由于您的答案已经超出您的接受范围 (:)),这是我的 0.02 美元:
template <typename Prefix, typename Postfix>
static auto quoted_(Prefix const& prefix, Postfix const& postfix) {
using namespace boost::spirit::x3;
return rule<struct _, std::string, true> {} = omit[prefix] >> *(char_ - postfix) >> omit[postfix];
}
现在你可以写了
auto header_name_brackets = quoted_('<', '>');
auto header_name_quotes = quoted_('"');
第二个假定明显的便利超载。
另一个错误
事实上,我认为有一个错误会跳过定界符内的空格。通过添加 lexeme[]
:
来修复它
template <typename Prefix, typename Postfix>
static auto quoted_(Prefix const& prefix, Postfix const& postfix) {
using namespace boost::spirit::x3;
return rule<struct _, std::string, true> {} = lexeme [
omit[prefix] >> *(char_ - postfix) >> omit[postfix]
];
}
查看完整演示:
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <cassert>
template <typename Prefix, typename Postfix>
static auto quoted_(Prefix const& prefix, Postfix const& postfix) {
using namespace boost::spirit::x3;
return rule<struct _, std::string, true> {} = lexeme [
omit[prefix] >> *(char_ - postfix) >> omit[postfix]
];
}
template <typename Prefix>
static auto quoted_(Prefix const& prefix) { return quoted_(prefix, prefix); }
int main() {
using boost::spirit::x3::space;
auto header_name_brackets = quoted_('<', '>');
auto header_name_quotes = quoted_('"');
{
auto s = std::string{"<my/file.hpp>"};
std::string parsed;
assert(phrase_parse(s.begin(), s.end(), header_name_brackets, space, parsed));
}
{
auto s = std::string{"\"my/file.hpp\""};
std::string parsed;
assert(phrase_parse(s.begin(), s.end(), header_name_quotes, space, parsed));
}
std::cout << "Bye\n";
}
下面的程序尝试解析 C++ header 包含字符串,例如 "my/file.hpp"
和 <my/file.hpp>
。由于我不明白的原因,我的代码无法解析 "
header。这是 Spirit 中的错误,还是我遗漏了一些明显的东西?
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <string>
#include <cassert>
using namespace boost::spirit::x3;
int main() {
auto header_name_brackets = '<' >> *(~char_('>')) >> '>';
auto header_name_quotes = '"' >> *(~char_('>')) >> '"';
{
auto s = std::string{"<my/file.hpp>"};
std::string parsed;
assert(phrase_parse(s.begin(), s.end(), header_name_brackets, space, parsed));
}
{
auto s = std::string{"\"my/file.hpp\""};
std::string parsed;
// this assert fails, but I don't know why.
assert(phrase_parse(s.begin(), s.end(), header_name_quotes, space, parsed));
}
}
您需要更改此规则:
auto header_name_quotes = '"' >> *(~char_('>')) >> '"';
至
auto header_name_quotes = '"' >> *(~char_('\"')) >> '"';
这对我有用:
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <string>
#include <cassert>
using namespace boost::spirit::x3;
int main() {
auto header_name_brackets = '<' >> *(~char_('>')) >> '>';
auto header_name_quotes = '"' >> *(~char_('"')) >> '"';
{
auto s = std::string{"<my/file.hpp>"};
std::string parsed;
assert(phrase_parse(s.begin(), s.end(), header_name_brackets, space, parsed));
}
{
auto s = std::string{"\"my/file.hpp\""};
std::string parsed;
// this assert fails, but I don't know why.
assert(phrase_parse(s.begin(), s.end(), header_name_quotes, space, parsed));
}
}
请注意,在第二种情况下,您需要匹配除 "
之外的所有字符,就像您在第一种情况下对 >
所做的那样。
由于您的答案已经超出您的接受范围 (:)),这是我的 0.02 美元:
template <typename Prefix, typename Postfix>
static auto quoted_(Prefix const& prefix, Postfix const& postfix) {
using namespace boost::spirit::x3;
return rule<struct _, std::string, true> {} = omit[prefix] >> *(char_ - postfix) >> omit[postfix];
}
现在你可以写了
auto header_name_brackets = quoted_('<', '>');
auto header_name_quotes = quoted_('"');
第二个假定明显的便利超载。
另一个错误
事实上,我认为有一个错误会跳过定界符内的空格。通过添加 lexeme[]
:
template <typename Prefix, typename Postfix>
static auto quoted_(Prefix const& prefix, Postfix const& postfix) {
using namespace boost::spirit::x3;
return rule<struct _, std::string, true> {} = lexeme [
omit[prefix] >> *(char_ - postfix) >> omit[postfix]
];
}
查看完整演示:
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <cassert>
template <typename Prefix, typename Postfix>
static auto quoted_(Prefix const& prefix, Postfix const& postfix) {
using namespace boost::spirit::x3;
return rule<struct _, std::string, true> {} = lexeme [
omit[prefix] >> *(char_ - postfix) >> omit[postfix]
];
}
template <typename Prefix>
static auto quoted_(Prefix const& prefix) { return quoted_(prefix, prefix); }
int main() {
using boost::spirit::x3::space;
auto header_name_brackets = quoted_('<', '>');
auto header_name_quotes = quoted_('"');
{
auto s = std::string{"<my/file.hpp>"};
std::string parsed;
assert(phrase_parse(s.begin(), s.end(), header_name_brackets, space, parsed));
}
{
auto s = std::string{"\"my/file.hpp\""};
std::string parsed;
assert(phrase_parse(s.begin(), s.end(), header_name_quotes, space, parsed));
}
std::cout << "Bye\n";
}