【问题标题】:Tokenize a string and include delimiters in C++在 C++ 中标记字符串并包含分隔符
【发布时间】:2009-10-02 18:07:57
【问题描述】:

我正在使用以下标记,但不确定如何在其中包含分隔符。

void Tokenize(const string str, vector<string>& tokens, const string& delimiters)
{

    int startpos = 0;
    int pos = str.find_first_of(delimiters, startpos);
    string strTemp;


    while (string::npos != pos || string::npos != startpos)
    {

        strTemp = str.substr(startpos, pos - startpos);
        tokens.push_back(strTemp.substr(0, strTemp.length()));

        startpos = str.find_first_not_of(delimiters, pos);
        pos = str.find_first_of(delimiters, startpos);

    }
}

【问题讨论】:

    标签: c++ tokenize


    【解决方案1】:

    C++ String Toolkit Library (StrTk)有如下解决方案:

    std::string str = "abc,123 xyz";
    std::vector<std::string> token_list;
    strtk::split(";., ",
                 str,
                 strtk::range_to_type_back_inserter(token_list),
                 strtk::include_delimiters);
    

    它应该导致 token_list 具有以下元素:

    令牌0 = "abc," 令牌1 = "123" 令牌2 = "xyz"

    更多例子可以在Here找到

    【讨论】:

      【解决方案2】:

      我现在有点草率,但这就是我最终的结果。我不想使用 boost,因为这是一项学校作业,我的老师希望我使用 find_first_of 来完成这项工作。

      感谢大家的帮助。

      vector<string> Tokenize(const string& strInput, const string& strDelims)
      {
       vector<string> vS;
      
       string strOne = strInput;
       string delimiters = strDelims;
      
       int startpos = 0;
       int pos = strOne.find_first_of(delimiters, startpos);
      
       while (string::npos != pos || string::npos != startpos)
       {
        if(strOne.substr(startpos, pos - startpos) != "")
         vS.push_back(strOne.substr(startpos, pos - startpos));
      
        // if delimiter is a new line (\n) then addt new line
        if(strOne.substr(pos, 1) == "\n")
         vS.push_back("\\n");
        // else if the delimiter is not a space
        else if (strOne.substr(pos, 1) != " ")
         vS.push_back(strOne.substr(pos, 1));
      
        if( string::npos == strOne.find_first_not_of(delimiters, pos) )
         startpos = strOne.find_first_not_of(delimiters, pos);
        else
         startpos = pos + 1;
      
              pos = strOne.find_first_of(delimiters, startpos);
      
       }
      
       return vS;
      }
      

      【讨论】:

        【解决方案3】:

        我真的不能按照你的代码,你能发布一个工作程序吗?

        无论如何,这是一个简单的分词器,无需测试边缘情况:

        #include <iostream>
        #include <string>
        #include <vector>
        
        using namespace std;
        
        void tokenize(vector<string>& tokens, const string& text, const string& del)
        {
            string::size_type startpos = 0,
                currentpos = text.find(del, startpos);
        
            do
            {
                tokens.push_back(text.substr(startpos, currentpos-startpos+del.size()));
        
                startpos = currentpos + del.size();
                currentpos = text.find(del, startpos);
            } while(currentpos != string::npos);
        
            tokens.push_back(text.substr(startpos, currentpos-startpos+del.size()));
        }
        

        示例输入,分隔符 = $$:

        Hello$$Stack$$Over$$$Flow$$$$!
        

        代币:

        Hello$$
        Stack$$
        Over$$
        $Flow$$
        $$
        !
        

        注意:我绝不会使用未经测试就编写的分词器!请使用boost::tokenizer

        【讨论】:

        • 我编辑了我的帖子以包含所有功能。我明白你做了什么,但分隔符将是一个字符串,字符串中的每个字符都是一个分隔符。像这样传递 " ,.!\n" 所以逗号、句号、感叹号和换行符也将被推入向量,但不会推入空格。这样我可以将向量连接回来并在向量项之间使用空格并重建字符串。
        • 逗号、句号、感叹号和包含空格的新行将作为分隔符。抱歉,想澄清一下。
        • 啊哈 :) 我想我错过了理解这个问题。我虽然你想在标记中包含分隔符。为什么不使用 boost::tokenizer?它完全符合您的要求。
        • 我可以在没有整个库的情况下获得分词器吗?
        • 您可以使用 boost::bcp 来提取所需的标头。没那么简单,你可以试试。
        【解决方案4】:

        如果分隔符是字符而不是字符串,那么您可以使用strtok

        【讨论】:

        • 谢谢..我差点忘了这个功能:P
        • strtok 使用分隔符标记,我相信。
        【解决方案5】:

        这取决于您是否需要前面的分隔符、后面的分隔符,或两者都需要,以及您想对字符串开头和结尾处可能没有分隔符之前/之后的字符串做什么。

        我将假设您想要每个单词及其前后的定界符,但不是任何单独的定界符字符串(例如,如果最后一个字符串后面有定界符)。

        template <class iter>
        void tokenize(std::string const &str, std::string const &delims, iter out) { 
            int pos = 0;
            do { 
                int beg_word = str.find_first_not_of(delims, pos);
                if (beg_word == std::string::npos) 
                    break;
                int end_word = str.find_first_of(delims, beg_word);
                int beg_next_word = str.find_first_not_of(delims, end_word);
                *out++ = std::string(str, pos, beg_next_word-pos);
                pos = end_word;
            } while (pos != std::string::npos);
        }
        

        目前,我把它写得更像是一个 STL 算法,它的输出采用迭代器,而不是假设它总是推送到一个集合上。由于它(目前)依赖于输入是一个字符串,因此它不使用迭代器作为输入。

        【讨论】:

        • 我想要字符串“测试字符串,在网络上。\n测试第一行。”成为这样的代币。我想要一个空格、一个逗号、一个句点和 \n 作为分隔符。测试字符串,在网络上。 \n 测试第一行。
        • 抱歉,没有正确发布。在单词分隔符之后,它应该将每件事都放在一个新的行上。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多