如何使用 boost::spirit 像正则表达式一样修改字符串?
How to use boost::spirit to modify a string like regex does?
我正在为我的程序编写一些领域特定语言,使用 JUCE::JavascriptEngine 作为脚本引擎。这将一个字符串作为输入然后对其进行解析,但我需要对字符串进行一些预处理以使其从我的 DSL 适应 JavaScript。预处理主要包括将一些术语包装在函数内部,并将对象名称放在函数前面。所以,例如,我想做这样的事情:
输入一些特殊的字符串"~/1/2"
...
将其包装在函数中:"find("~/1/2")"
...
然后附加一个对象:"someObject.find("~/1/2")"
(对象名必须是一个变量)。
我一直在为此使用正则表达式(现在我有两个问题...)。正则表达式变得越来越复杂和不可读,而且它遗漏了很多特殊情况。因为我正在做的是语法,我想我会从正则表达式升级到一个合适的解析器(现在我有三个问题......)。经过大量研究,我选择了Boost.Spirit。我一直在浏览文档,但它并没有带我走向正确的方向。有人可以建议我如何使用这个库以我正在寻找的方式操作字符串吗?鉴于我只是想操作一个字符串,对存储解析后的数据不感兴趣,我是否需要使用 karma
进行输出,或者我可以使用 qi
或 [=16 输出字符串=], 解析过程中?
如果我在这里走错了路,请随时重新引导我。
这似乎太宽泛了,无法回答。
您正在做的是解析 输入,并将其转换为其他内容。你没有做的是 find/replace(否则你可以使用正则表达式)。
当然你可以像正则表达式那样做,但我不确定它能给你带来什么:
template <typename It, typename Out>
Out preprocess(It f, It l, Out out) {
namespace qi = boost::spirit::qi;
using boost::spirit::repository::qi::seek;
auto passthrough = [&out](boost::iterator_range<It> ignored, auto&&...) {
for (auto ch : ignored) *out++ = ch;
};
auto transform = [&out](std::string const& literal, auto&&...) {
for (auto ch : "someObject.find(\"~"s) *out++ = ch;
for (auto ch : literal) *out++ = ch;
for (auto ch : "\")"s) *out++ = ch;
};
auto pattern = qi::copy("\"~" >> (*~qi::char_('"')) >> '"');
qi::rule<It> ignore = qi::raw[+(!pattern >> qi::char_)] [passthrough];
qi::parse(f, l, -qi::as_string[pattern][transform] % ignore);
return out;
}
这种编写方式的好处在于它可以与任何源迭代器一起使用:
for (std::string const input : {
R"(function foo(a, b) { var path = "~/1/2"; })",
})
{
std::cout << "Input: " << input << "\n";
std::string result;
preprocess(begin(input), end(input), back_inserter(result));
std::cout << "Result: " << result << "\n";
}
std::cout << "\n -- Or directly transformed stdin to stdout:\n";
preprocess(
boost::spirit::istream_iterator(std::cin >> std::noskipws), {},
std::ostreambuf_iterator<char>(std::cout));
看到它Live On Coliru,打印输出:
Input: function foo(a, b) { var path = "~/1/2"; }
Result: function foo(a, b) { var path = someObject.find("~/1/2"); }
-- Or directly transformed stdin to stdout:
function bar(c, d) { var path = someObject.find("~/1/42"); }
但这非常有限,因为如果这些东西是评论或 multiline strings 等的一部分,它甚至不会做正确的事情
因此,您可能需要一个专用库,它 知道如何解析 javascript 并使用它来进行转换,例如(当谷歌搜索 tooling library preprocess javascript transform
): https://clojurescript.org/reference/javascript-library-preprocessing
我正在为我的程序编写一些领域特定语言,使用 JUCE::JavascriptEngine 作为脚本引擎。这将一个字符串作为输入然后对其进行解析,但我需要对字符串进行一些预处理以使其从我的 DSL 适应 JavaScript。预处理主要包括将一些术语包装在函数内部,并将对象名称放在函数前面。所以,例如,我想做这样的事情:
输入一些特殊的字符串"~/1/2"
...
将其包装在函数中:"find("~/1/2")"
...
然后附加一个对象:"someObject.find("~/1/2")"
(对象名必须是一个变量)。
我一直在为此使用正则表达式(现在我有两个问题...)。正则表达式变得越来越复杂和不可读,而且它遗漏了很多特殊情况。因为我正在做的是语法,我想我会从正则表达式升级到一个合适的解析器(现在我有三个问题......)。经过大量研究,我选择了Boost.Spirit。我一直在浏览文档,但它并没有带我走向正确的方向。有人可以建议我如何使用这个库以我正在寻找的方式操作字符串吗?鉴于我只是想操作一个字符串,对存储解析后的数据不感兴趣,我是否需要使用 karma
进行输出,或者我可以使用 qi
或 [=16 输出字符串=], 解析过程中?
如果我在这里走错了路,请随时重新引导我。
这似乎太宽泛了,无法回答。
您正在做的是解析 输入,并将其转换为其他内容。你没有做的是 find/replace(否则你可以使用正则表达式)。
当然你可以像正则表达式那样做,但我不确定它能给你带来什么:
template <typename It, typename Out>
Out preprocess(It f, It l, Out out) {
namespace qi = boost::spirit::qi;
using boost::spirit::repository::qi::seek;
auto passthrough = [&out](boost::iterator_range<It> ignored, auto&&...) {
for (auto ch : ignored) *out++ = ch;
};
auto transform = [&out](std::string const& literal, auto&&...) {
for (auto ch : "someObject.find(\"~"s) *out++ = ch;
for (auto ch : literal) *out++ = ch;
for (auto ch : "\")"s) *out++ = ch;
};
auto pattern = qi::copy("\"~" >> (*~qi::char_('"')) >> '"');
qi::rule<It> ignore = qi::raw[+(!pattern >> qi::char_)] [passthrough];
qi::parse(f, l, -qi::as_string[pattern][transform] % ignore);
return out;
}
这种编写方式的好处在于它可以与任何源迭代器一起使用:
for (std::string const input : {
R"(function foo(a, b) { var path = "~/1/2"; })",
})
{
std::cout << "Input: " << input << "\n";
std::string result;
preprocess(begin(input), end(input), back_inserter(result));
std::cout << "Result: " << result << "\n";
}
std::cout << "\n -- Or directly transformed stdin to stdout:\n";
preprocess(
boost::spirit::istream_iterator(std::cin >> std::noskipws), {},
std::ostreambuf_iterator<char>(std::cout));
看到它Live On Coliru,打印输出:
Input: function foo(a, b) { var path = "~/1/2"; }
Result: function foo(a, b) { var path = someObject.find("~/1/2"); }
-- Or directly transformed stdin to stdout:
function bar(c, d) { var path = someObject.find("~/1/42"); }
但这非常有限,因为如果这些东西是评论或 multiline strings 等的一部分,它甚至不会做正确的事情
因此,您可能需要一个专用库,它 知道如何解析 javascript 并使用它来进行转换,例如(当谷歌搜索 tooling library preprocess javascript transform
): https://clojurescript.org/reference/javascript-library-preprocessing