如何解决如何将带括号的字符串解析为具有给定分隔符的字符串列表
我的任务是解析方括号中的字符串,例如
[foo | bar | foobar]
到vector
中的std::strings
。
在这种情况下,
vector
应该以内容{"foo","bar","foobar"}
结尾。
这些括号可以嵌套。例如,给定的带括号的字符串
[[john | doe] | [ bob | dylan]]
将成为{ "[john | doe]","[bob | dylan] }
“
到目前为止,我能做到的最好的是
int main(int argc,char ** argv)
{
const std::string input {argv[1]};
std::vector<std::string> res;
qi::phrase_parse(input.cbegin(),input.cend(),'['
>> *qi::lexeme[ +(qi::char_ - '|') >> '|']
> -qi::lexeme[ +(qi::char_ - ']') >> ']' ],qi::space,res);
for (const auto& v: res)
std::cout << v <<std::endl;
return 0;
}
对于嵌套的情况非常失败。有人可以指出我正确的方向吗?
注1:嵌套的案例可以不止一个。
注2:我欢迎任何更简单的解决方案,即使不使用Boost Spirit。
解决方法
这是一个简单的C ++解析器,它基于括号是平衡的假设,即每个[
都有一个]
。
bracket
是左括号的数量。当该数字为1
时,我们将做出至关重要的决定。
#include <iostream>
#include <vector>
#include <string>
#include <string_view>
bool edge(const int num){
return num == 1;
}
int main(){
std::vector<std::string> all;
std::string line;
// std::getline(std::cin,line);
line = "[[john | doe] | [ bob | dylan]]";
int bracket = 0;
std::string::size_type start = 0;
for(int i = 0; i < line.size(); i++){
const char c = line[i];
if(c == '['){
bracket++;
if(edge(bracket)){
start = i + 1;
}
}
if(c == ']'){
if(edge(bracket)){
all.push_back(line.substr(start,i - start));
}
bracket--;
}
if(c == '|' && edge(bracket)){
all.push_back(line.substr(start,i - start));
start = i + 1;
}
}
for(std::string_view t : all){
std::cout << t << std::endl;
}
}
,
如果要嵌套的字符串列表,首先需要一个可以存储嵌套列表的结果。幸运的是,在C ++ 17中,您可以具有正向引用向量(只要在某些时候定义了它们)。因此,您可以将类型设为列表,其中每个项目都是字符串或另一个列表:
struct Expr : std::vector<
boost::variant<
std::string,Expr>>
{
using std::vector<boost::variant<std::string,Expr>>::vector;
};
语法很简单。请注意,它是递归的-Term
可以嵌套Expr
:
WORD = /[^\[\|\]]+/
Term = WORD | Expr
Expr = '[' Term ('|' Term)* ']';
您可以分别表达每个规则。 Boost Spirit Qi方便地具有%
运算符,该运算符解析定界列表并将其插入到容器中。
using It = std::string::const_iterator;
using Sk = qi::space_type;
qi::rule<It,std::string(),Sk> word;
qi::rule<It,boost::variant<std::string,Expr>(),Sk> term;
qi::rule<It,Expr(),Sk> expr;
word = +(qi::char_ - '[' - '|' - ']');
term = word | expr;
expr = '[' >> (term % '|') >> ']';
然后qi::phrase_parse
将执行您想要的操作:
Expr res;
qi::phrase_parse(input.cbegin(),input.cend(),expr,qi::space,res);
演示:https://godbolt.org/z/5W993s
,这个更简单的版本似乎就是您想要的:
qi::phrase_parse(input.cbegin(),'['
>> qi::lexeme[ +~qi::char_("|]") ] % '|'
>> ']',res);
它将解析:
"foo "
"bar "
"foobar"
也许您实际上并不希望将空格作为比赛的一部分。那么它甚至可以更简单:
qi::phrase_parse(input.cbegin(),'['
>> qi::lexeme[ +(qi::graph - qi::char_("|]")) ] % '|'
>> ']',res);
注意:如果您使用的是C ++ 14,请考虑使用X3:Live On Coliru。编译起来会快很多
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。