我想使用Boost.Tokenize
将字符串拆分为标记。引号或括号中的文本必须是单个整个标记。更具体地说,我需要拆分像
"one (two),three" four (five "six".seven ) eight(nine, ten)
成为像
这样的标记one (two),three
four
(five "six".seven )
eight
(nine, ten)
或者
one (two),three
four
(
five "six".seven
)
eight
(
nine, ten
)
我知道the way用引号标记文本,但我不知道如何同时对文本中的文本进行标记。也许需要实施TokenizerFunction
如我所描述的那样如何分割字符串?
答案 0 :(得分:1)
TokenizerFunction是一个有两种方法的仿函数,这两种方法都不应该很难实现。第一个是reset
,用于重置仿函数可能具有的任何状态,另一个是operator()
,它带有三个参数。前两个是迭代器,第三个是生成的令牌。
下面的算法很简单。首先,我们跳过任何空格。我们期望第一个非空格字符是三种中的一种。如果它是引号或左括号,那么我们搜索直到找到相应的结束分隔符并返回我们发现的令牌,注意引号应该被剥离,但显然要保留括号。如果第一个字符是其他字符,那么我们搜索下一个分隔符并返回它。
template <
typename Iter = std::string::const_iterator,
typename Type = std::string
>
struct QuoteParenTokenizer
{
void reset() { }
bool operator()(Iter& next, Iter end, Type& tok) const
{
while (next != end && *next == ' ')
++next;
if (next == end)
return false; // nothing left to read
switch (*next) {
case '"': {
++next; // skip token start
Item const quote = std::find(next, end, '"');
if (quote == end)
return false; // unterminated token
tok.assign(next, quote);
next = quote;
++next;
break;
}
case '(': {
Iter paren = std::find(next, end, ')');
if (paren == end)
return false; // unterminated token
++paren; // include the parenthesis
tok.assign(next, paren);
next = paren;
break;
}
default: {
Iter const first = next;
while (next != end && *next != ' ' && *next != '"' && *next != '(')
++next;
tok.assign(first, next);
}
}
return true;
}
};
您将其实例化为tokenizer<QuoteParenTokenizer<> >
。如果您有不同的迭代器类型或不同的令牌类型,则需要在tokenizer
和 QuoteParenTokenizer
的模板参数中指明它们。
如果您需要处理转义的分隔符字符,您可以获得更好的效果。如果您需要括号括起来的表达式,事情就会变得棘手。
请注意,截至目前,上述代码尚未经过测试。