2016-06-11 44 views
1

我想检查一个文件的所有枚举(这只是一个MCVE,所以没有复杂),并且枚举的名称应该存储在std::vector我构建像这样的解析器:从助推精灵x3解析器返回的向量中的空字符串

auto const any = x3::rule<class any_id, const x3::unused_type>{"any"} 
       = ~x3::space; 

auto const identifier = x3::rule<class identifier_id, std::string>{"identifier"} 
         = x3::lexeme[x3::char_("A-Za-z_") >> *x3::char_("A-Za-z_0-9")]; 

auto const enum_finder = x3::rule<class enum_finder_id, std::vector<std::string>>{"enum_finder"} 
         = *(("enum" >> identifier) | any); 

当我试图用这个enum_finder字符串解析成一个std::vector,该std::vector还含有大量的空字符串。 为什么这个解析器还将空字符串解析成矢量?

+3

这是** **不是一个MCVE。这不是最小的。这不完整。这是无法验证的。你有样品输入吗? – sehe

+0

@sehe [Here](http://melpon.org/wandbox/permlink/51qsx3qf6z8flvi4)是完整的东西(遗憾的是只使用boost 1.60,因为我没有访问我的电脑,我不认为任何在线编译器有1.61可用)。看来,不知道是否打算或错误,当'a'的属性是std :: string和'b'未使用时'a | b'的属性现在是std :: string而不是boost :: optional 。 – llonesmiz

+0

FWIW我想我刚刚发布了一个SSCCE的好例子。 – sehe

回答

2

我假设你想要解析“枚举”出自由的形式文本忽略空格。

你真正想要的是("enum" >> identifier | any)合成optional<string>。可悲的是,你得到的是variant<string, unused_type>或其他。

当您将anyx3::omit[any]包装在一起时 - 它仍然是unused_type。

计划B:既然你真的只是解析由“什么”分隔反复枚举的IDS,为什么不使用列表操作符:

 ("enum" >> identifier) % any 

这工作一点点。现在进行一些调整:让我们避免按角色吃“任何”字符。事实上,我们可以很可能只是消耗整个空格分隔字:(注意:+~space相当于+graph):

auto const any = x3::rule<class any_id>{"any"} 
       = x3::lexeme [+x3::graph]; 

接下来,以允许多个假字连续接受有诀窍,使列表的主题解析器可选:

 -("enum" >> identifier) % any; 

解析正确。查看完整的演示:

DEMO

Live On Coliru

#include <boost/spirit/home/x3.hpp> 
namespace x3 = boost::spirit::x3; 

namespace parser { 
    using namespace x3; 
    auto any   = lexeme [+~space]; 
    auto identifier = lexeme [char_("A-Za-z_") >> *char_("A-Za-z_0-9")]; 
    auto enum_finder = -("enum" >> identifier) % any; 
} 

#include <iostream> 
int main() { 

    for (std::string input : { 
      "", 
      " ", 
      "bogus", 
      "enum one", 
      "enum one enum two", 
      "enum one bogus bogus more bogus enum two [email protected]#[email protected]#Yay", 
     }) 
    { 
     auto f = input.begin(), l = input.end(); 
     std::cout << "------------ parsing '" << input << "'\n"; 

     std::vector<std::string> data; 
     if (phrase_parse(f, l, parser::enum_finder, x3::space, data)) 
     { 
      std::cout << "parsed " << data.size() << " elements:\n"; 
      for (auto& el : data) 
       std::cout << "\t" << el << "\n"; 
     } else { 
      std::cout << "Parse failure\n"; 
     } 

     if (f!=l) 
      std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n"; 
    } 

} 

打印:

------------ parsing '' 
parsed 0 elements: 
------------ parsing ' ' 
parsed 0 elements: 
------------ parsing 'bogus' 
parsed 0 elements: 
------------ parsing 'enum one' 
parsed 1 elements: 
    one 
------------ parsing 'enum one enum two' 
parsed 1 elements: 
    one 
------------ parsing 'enum one bogus bogus more bogus enum two [email protected]#[email protected]#Yay' 
parsed 2 elements: 
    one 
    two 
+0

非常感谢你是我的助推精神英雄 – Exagon

+0

但在例子“enum one enum two”为什么它只能找到一个元素?如果解析另一个,它会更好吗? – Exagon

+0

@Exagon我认为使用'auto any = lexeme [*(〜space - “enum”)];'应该可以工作,但我无法测试它。 – llonesmiz