Boost.Tokenizer用于引号和圆括号

Boost.Tokenizer for quotation marks and parentheses

本文关键字:圆括号 Tokenizer 用于 Boost      更新时间:2023-10-16

我想使用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
)

我知道用引号标记文本的方法,但我不知道如何同时用父子关系标记文本。可能需要实现TokenizerFunction
如何像我描述的那样拆分字符串?

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<> >。如果您有不同的迭代器类型或不同的令牌类型,则需要在tokenizerQuoteParenTokenizer的模板参数中指示它们。

如果您需要处理转义的分隔符字符,您可能会变得更喜欢。如果你需要插入括号的表达式来嵌套,事情会更棘手。

请注意,截至目前,上述代码尚未经过测试。