三种实现方式:
- 有升压精神
- 使用 Boost 正则表达式
- 手写解析器
用精神振奋
以下是我如何使用 Boost Spirit 执行此操作。这可能看起来有点矫枉过正,但经验告诉我,一旦拆分输入文本,您可能需要更多的解析逻辑。
当您从“仅拆分标记”扩展到具有生产规则的真正语法时,Boost Spirit 会大放异彩。
Live On Coliru
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
int main() {
std::string const sentence = "My dog Fluffy\\ Cake likes to jump";
using It = std::string::const_iterator;
It f = sentence.begin(), l = sentence.end();
std::vector<std::string> words;
bool ok = qi::phrase_parse(f, l,
*qi::lexeme [ +('\\' >> qi::char_ | qi::graph) ], // words
qi::space - "\\ ", // skipper
words);
if (ok) {
std::cout << "Parsed:\n";
for (auto& w : words)
std::cout << "\t'" << w << "'\n";
} else {
std::cout << "Parse failed\n";
}
if (f != l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
使用 Boost 正则表达式
这看起来很简洁,但是
Live On Coliru
#include <iostream>
#include <boost/regex.hpp>
#include <boost/algorithm/string_regex.hpp>
#include <vector>
int main() {
std::string const sentence = "My dog Fluffy\\ Cake likes to jump";
std::vector<std::string> words;
boost::algorithm::split_regex(words, sentence, boost::regex("(?<!\\\\)\\s"), boost::match_default);
for (auto& w : words)
std::cout << " '" << w << "'\n";
}
使用 c++11 原始文字,您可以稍微不那么晦涩地编写正则表达式:boost::regex(R"((?<!\\)\s)"),意思是“任何不跟在反斜杠后面的空格”
手写解析器
这有点乏味,但就像 Spirit 语法一样是完全通用的,并且可以提供很好的性能。
但是,一旦您开始增加语法的复杂性,它就不会像 Spirit 方法那样优雅地扩展。一个优点是编译代码的时间比 Spirit 版本少。
Live On Coliru
#include <iostream>
#include <iterator>
#include <vector>
template <typename It, typename Out>
Out tokens(It f, It l, Out out) {
std::string accum;
auto flush = [&] {
if (!accum.empty()) {
*out++ = accum;
accum.resize(0);
}
};
while (f!=l) {
switch(*f) {
case '\\':
if (++f!=l && *f==' ')
accum += ' ';
else
accum += '\\';
break;
case ' ': case '\t': case '\r': case '\n':
++f;
flush();
break;
default:
accum += *f++;
}
}
flush();
return out;
}
int main() {
std::string const sentence = "My dog Fluffy\\ Cake likes to jump";
std::vector<std::string> words;
tokens(sentence.begin(), sentence.end(), back_inserter(words));
for (auto& w : words)
std::cout << "\t'" << w << "'\n";
}