【问题标题】:Splitting a string with multiple delimiters in C++ [duplicate]在 C++ 中使用多个分隔符拆分字符串 [重复]
【发布时间】:2018-08-18 11:47:23
【问题描述】:

所以我必须将短语:“大家好!这是:COSC-1436,SP18”分成单独的标记,忽略任何标点符号减去破折号。所以输出应该是:

你好

大家

这个

COSC-1436

SP18

然后我必须加密我得到的每个令牌。我只是在使用多个分隔符时遇到了麻烦。这是我目前拥有的。

函数原型: void tokenize(const string&, const string&, vector<string>&);

函数调用: tokenize(code, " .,:;!?", tokens);

函数定义:

void tokenize(const string& str, const string& delim, vector<string>& tokens)
{
    int tokenStart = 0;

    int delimPos = str.find_first_of(delim);

    while(delimPos != string::npos)
    {
        string tok = str.substr(tokenStart, delimPos - tokenStart);

        tokens.push_back(tok);

        delimPos++;

        tokenStart = delimPos;

        delimPos = str.find_first_of(delim, delimPos);

        if(delimPos == string::npos)
        {
            string tok = str.substr(tokenStart, delimPos - tokenStart);

            tokens.push_back(tok);
        }   
    }
}

唯一的问题是程序遇到标点符号的地方现在有作为空格的标记。有什么建议吗?

【问题讨论】:

    标签: c++ string split token delimiter


    【解决方案1】:

    找到分隔符后,您应该将子字符串开头移动到字符 first_not_of 您的分隔符。基本改变:

    delimPos++;
    

    到:

    delimPos = str.find_first_not_of(delim, delimPos + 1);
    

    这将确保当您连续有 2 个或更多分隔符时,delimPos 会移到最后一个之外。

    您也可以试试这个:

    #include <iostream> 
    #include <string>
    
    int main()
    {
        std::string str = "Hello, everyone! This is: COSC-1436, SP18";
        std::string const delims{ " .,:;!?" };
    
        size_t beg, pos = 0;
        while ((beg = str.find_first_not_of(delims, pos)) != std::string::npos)
        {
            pos = str.find_first_of(delims, beg + 1);
            std::cout << str.substr(beg, pos - beg) << std::endl;
        }
    
        return 0;
    }
    

    https://ideone.com/LJota9

    Hello
    everyone
    This
    is
    COSC-1436
    SP18
    

    【讨论】:

    • 非常感谢您的帮助!但我是一个编码新手,我想将你所说的实现到我已经拥有的代码中,这样我就可以完全理解它。我将在我的代码中进行哪些更改以将我的子字符串开始为我的分隔符的 first_not_of 字符?
    • @Tristan 强调了您需要更改的内容才能使其在我的答案中发挥作用
    • 老兄,非常感谢你,你是个传奇!现在一切正常!
    【解决方案2】:

    您可以只使用std::regex_iterator,因为这正是它的设计目的。

    #include <regex>
    #include <iostream>
    #include <string>
    
    int main()
    {
        const std::string s = "Hello, everyone! This is: COSC-1436, SP18";
    
        std::regex words_regex("[^\\s.,:;!?]+");
        auto words_begin = std::sregex_iterator(s.begin(), s.end(), words_regex);
        auto words_end = std::sregex_iterator();
    
        for (std::sregex_iterator i = words_begin; i != words_end; ++i)
            std::cout << (*i).str() << '\n';
    }
    

    完整程序的输出将是这个。

    Hello
    everyone
    This
    is
    COSC-1436
    SP18
    

    【讨论】:

    • 那是纯 C++11。
    • 没错,我误读了您使用的是std::regex(不是std::basic_regex)。
    • 请注意,对于这种简单的情况,正则表达式不要太多,而且比 Killzone Kid 简单解决方案 berlow 慢约 30 倍(这对于大于 10 MB 的大文件很重要)
    • “太多”是相当主观的。我很乐意从 10 MB 文件中查看您的实际测量数据,因为正则表达式的成本在于编译它,而且它们往往比暴力线​​性比较运行得更快、更有效(O(log n))( O(n^2))。
    猜你喜欢
    • 2022-01-13
    • 2011-06-27
    • 2018-04-20
    • 2016-11-17
    • 2020-04-17
    • 1970-01-01
    • 2017-01-24
    • 2020-01-07
    相关资源
    最近更新 更多