增强精神解析器:绕过贪婪的克莱恩*
boost spirit parser : getting around the greedy kleene *
我有一个语法,应该匹配字符序列,后面跟着第一个字符的子集。 例如
boost::spirit::qi::rule<Iterator, std::string()> grammar = *char_('a', 'z') >> char_('b', 'z').
由于 kleene * 是贪婪的运算符,它会吞噬所有内容,没有为第二个解析器留下任何东西,因此它无法匹配像"abcd"这样的字符串
有什么办法可以解决这个问题吗?
是的,尽管您的示例缺乏上下文供我们了解。
我们需要知道什么构成完全匹配,因为现在"b"将是有效的匹配,而"bb"或"bbb"是有效的匹配。那么当输入是"bbb"时,匹配的是什么?(b,bb或bbb?
当你回答(可能)"显然,bbb"时,那么"bbbb"会发生什么?何时停止接受子集中的字符?如果你想让小星不贪婪,你还希望它贪婪吗?
上面的对话框很烦人,但目标是让你思考你需要什么。你不需要一个不贪婪的克莱恩星。您可能希望对最后一个字符进行验证约束。最有可能的是,如果输入有"bbba",你不想简单地匹配"bbb",留下"a"。相反,您可能希望停止解析,因为"bbba"不是有效的令牌。
假设...
我会写
grammar = +char_("a-z") >> eps(px::back(_val) != 'a');
这意味着只要匹配,我们至少接受1 个字符,断言最后一个字符不是a
。
住在科里鲁
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
template <typename It>
struct P : qi::grammar<It, std::string()>
{
P() : P::base_type(start) {
using namespace qi;
start = +char_("a-z") >> eps(px::back(_val) != 'a');
}
private:
qi::rule<It, std::string()> start;
};
#include <iomanip>
int main() {
using It = std::string::const_iterator;
P<It> const p;
for (std::string const input : { "", "b", "bb", "bbb", "aaab", "a", "bbba" }) {
std::cout << std::quoted(input) << ": ";
std::string out;
It f = input.begin(), l = input.end();
if (parse(f, l, p, out)) {
std::cout << std::quoted(out);
} else {
std::cout << "(failed) ";
}
if (f != l)
std::cout << " Remaining: " << std::quoted(std::string(f,l));
std::cout << "n";
}
}
指纹
"": (failed)
"b": "b"
"bb": "bb"
"bbb": "bbb"
"aaab": "aaab"
"a": (failed) Remaining: "a"
"bbba": (failed) Remaining: "bbba"
奖金
一种更通用(尽管效率较低)的方法是将主要角色与前瞻性断言匹配,即它不是同类角色中的最后一个:
start = *(char_("a-z") >> &char_("a-z")) >> char_("b-z");
这里的好处是不需要使用凤凰城:
住在科里鲁
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
template <typename It>
struct P : qi::grammar<It, std::string()>
{
P() : P::base_type(start) {
using namespace qi;
start = *(char_("a-z") >> &char_("a-z")) >> char_("b-z");
}
private:
qi::rule<It, std::string()> start;
};
#include <iomanip>
int main() {
using It = std::string::const_iterator;
P<It> const p;
for (std::string const input : { "", "b", "bb", "bbb", "aaab", "a", "bbba" }) {
std::cout << std::quoted(input) << ": ";
std::string out;
It f = input.begin(), l = input.end();
if (parse(f, l, p, out)) {
std::cout << std::quoted(out);
} else {
std::cout << "(failed) ";
}
if (f != l)
std::cout << " Remaining: " << std::quoted(std::string(f,l));
std::cout << "n";
}
}
相关文章:
- 芬威克树(BIT).找到具有给定累积频率的最小索引,单位为 O(logN)
- 贪婪算法编号列表
- 莱克斯没有返回我想要的东西
- 使用莱布尼茨公式的 Pi 近似
- 拉帕克C++实矩阵反演
- 拉帕克C++复杂的矩阵反演
- 运行莱文斯坦代码时出现问题
- 斯塔克,堆栈,也可以在底部和顶部添加整数
- 增强精神解析器:绕过贪婪的克莱恩*
- C++记忆霍夫莱恩斯·
- 提升灵气:省略克莱恩星辰解析器中的元素
- 克洛克沃恩.无符号字符上的签名位
- 霍夫莱恩不工作
- 精神莱克斯->气语法问题
- 不急于提升灵气的克莱恩星
- 图书馆访问比格尔骨黑(3.8 克恩 - 埃)
- 提升::精神::莱克斯;如何指定令牌"||"?
- 提升::精神::业力:复制在重复或克莱恩星中不起作用?
- 使用Boost时的空白提示符.灵气和莱克斯
- 莱克斯:强制扫描