Loading

C++ 常见问题:字符串分割

在一些编程练习中,经常会对字符串进行处理,往往处理之前都会对字符串进行分割来提取各部分信息。在C++中虽然没有像python那样提供split这样直接的字符串分割函数,但也有一些其他的方法能够对其进行分割,下面介绍几种C++中常用的字符串分割方法。

方法一:通过 string 成员函数实现

  • find() 函数

    • 原型: size_t find (const string& str, size_t pos = 0) const;
    • 功能:查找子字符串第一次出现的位置。
    • 参数说明:str为子字符串,pos为初始查找位置。
    • 返回值:找到的话返回第一次出现的位置,否则返回string::npos。
  • substr()函数:

    • 原型: string substr (size_t pos = 0, size_t len = npos) const;
    • 功能:在原字符串中截取子字符串。
    • 参数说明:pos为起始位置,len为要截取子字符串的长度。
    • 返回值:子字符串。
vector<string> split(const string &str, const string &pattern)
{
    vector<string> res;
    if(str == "")
        return res;
    //在字符串末尾也加入分隔符,方便截取最后一段
    string strs = str + pattern;
    size_t pos = strs.find(pattern);

    while(pos != strs.npos)
    {
        string temp = strs.substr(0, pos);
        res.push_back(temp);
        //去掉已分割的字符串,在剩下的字符串中进行分割
        strs = strs.substr(pos+1, strs.size());
        pos = strs.find(pattern);
    }

    return res;
}

vector<string> split(const string& str, const string& pattern)
{
    size_t pos1, pos2;
    pos2 = str.find(pattern);
    pos1 = 0;
    vector<string> result;
    while(npos != pos2)
    {
        result.push_back(str.substr(pos1, pos2-pos1));
        pos1 = pos2 + pattern.size();   // 跳过模式串
        pos2 = str.find(pattern, pos1);
    }

    if(pos1 != str.length())
        result.push_back(str.substr(pos1));
    return result;
}

方法二:通过 strtok 函数实现

  • strtok为C语言中的字符串分割函数,其具体解释如下:
    • 原型:char * strtok ( char * str, const char * delimiters );
    • 功能:分割字符串str,delimiters为指定的分割符,可以有多个。
    • 说明:strtok只能接受 C 风格的字符串,如果是 string 类型,可以使用 c_str 函数进行转换。strtok() 用来将字符串分割成一个个片段。参数s指向欲分割的字符串,参数delim则为分割字符串,当strtok()在参数s的字符串中发现到参数delim的分割字符时 则会将该字符改为\0 字符。在第一次调用时,strtok()必需给予参数s字符串,往后的调用则将参数s设置成NULL。每次调用成功则返回被分割出片段的指针。
vector<string> split(const string &str, const string &pattern)
{
    char * strc = new char[strlen(str.c_str())+1];
    strcpy(strc, str.c_str());   //string转换成C-string
    vector<string> res;
    char* temp = strtok(strc, pattern.c_str());
    while(temp != NULL)
    {
        res.push_back(string(temp));
        temp = strtok(NULL, pattern.c_str());
    }
    delete[] strc;
    return res;
}

方法三:通过 stringstream 实现

  • stringstream 为字符串输入输出流,继承自iostream,灵活地使用 stringstream 流可以完成很多字符串处理功能,例如字符串和其他类型的转换,字符串分割等。在这里,我们使用其实现字符串分割功能。注意 stingstream 的使用需要包含 sstream 头文件。
vector<string> split(const string &str, const char pattern)
{
    vector<string> res;
    stringstream input(str);   //读取str到字符串流中
    string temp;
    // 使用 getline 函数从字符串流中读取,遇到分隔符时停止,和从 cin 中读取类似
    // 注意, getline 默认是可以读取空格的
    while(getline(input, temp, pattern))
        res.push_back(temp);

    return res;
}

方法四:通过 boost 库中的 split 函数

boost库有很多方法来实现split,也包含了一个split函数,可以直接使用,非常实用而且强大,但是得自己下载boost库。使用代码如下

#include <boost/algorithm/string.hpp>
#include <iostream>
#include <string>
#include <vector>

using namespace std;
using namespace boost;

void print( vector <string> & v )
{
  for (size_t n = 0; n < v.size(); n++)
    cout << "\"" << v[ n ] << "\"\n";
  cout << endl;
}

int main()
{
    string s = "a,b, c ,,e,f,";
    vector <string> fields;

    cout << "Original = \"" << s << "\"\n\n";

    cout << "Split on \',\' only\n";
    split( fields, s, is_any_of( "," ) );
    print( fields );

    cout << "Split on \" ,\"\n";
    split( fields, s, is_any_of( " ," ) );
    print( fields );

    cout << "Split on \" ,\" and elide delimiters\n"; 
    split( fields, s, is_any_of( " ," ), token_compress_on );
    print( fields );

    return 0;
}

输出结果:

Original = "a,b, c ,,e,f,"

Split on ',' only
"a"
"b"
" c "
""
"e"
"f"
""

Split on " ,"
"a"
"b"
""
"c"
""
""
"e"
"f"
""

Split on " ," and elide delimiters
"a"
"b"
"c"
"e"
"f"
""

在C++中还有很多方法来实现split 函数,cplusplus.com有个C++ split 专题,详细比较分析了几种实现方法(见下图)。链接见文末参考文献。

参考文献

posted @ 2022-04-12 16:15  锦瑟,无端  阅读(291)  评论(0编辑  收藏  举报