如何使用 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