victory的博客

长安一片月,万户捣衣声

0%

C++ | 字符串分割

C++字符串分割

字符串分割是编程中经常遇到的一个问题,采用C++语言实现字符串分割与其他语言有所不同,下面将采用C++语言实现字符串分割并对用到的字符串操作函数进行详细的描述。

  • 字符串分割Java实现

    Java通过调用String.split(String delimiter)方法可直接完成对字符串的分割。

    1
    2
    3
    4
    5
    6
    7
    public static void  main(String[] args){
    String str = "I am a good programmer!";
    String[] splited_string = str.split(" ");
    for(String s : splited_string){
    System.out.println(s);
    }
    }
  • 字符串分割Python实现

    python实现字符串分割代码更为间接,很多功能使用python实现仅用一行代码,江湖上称之为“一行流”。

    1
    print("I am a good programmer!".split(" "))
  • 字符串分割C++实现

    比起Java和python实现,采用C++实现字符串分割的过程则略为繁琐。需要用到c_str()、strcpy()、strtok()等方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    #include <cstring>
    #include <string>
    #include <vector>
    #include <iostream>

    using namespace std;

    void splitString(const string &str, const string &split, vector<string> &res)
    {
    // str:要处理的字符串
    // split:分隔符
    // res:存放分割后的结果
    char *strc = new char[str.size() + 1];

    strcpy(strc, str.c_str());

    char *temp = strtok(strc, split.c_str());
    //strtok()的源码为char *__cdecl strtok(char * __restrict__ _Str,const char * __restrict__ _Delim)
    //strtok接收的参数时char*类型,因此进行字符串分割前需要将string类型的字符串转为char*类型

    while (temp != NULL)
    {
    res.push_back(string(temp));
    temp = strtok(NULL, split.c_str()); //strtok第一个参数传入NULL,使用之前保存的SAVE_PTR定位下一个待处理的字符的位置
    }
    delete[] strc;
    }

    int main(){
    vector<string> result;
    splitString("I am a good programmer!", " ", result);

    cout << "分割的子字符串的数量为:" << result.size() << endl;
    cout << "分割后的字符串为:" << endl;
    for(int i = 0; i < result.size(); ++i) {
    std::cout << result[i] << endl;
    }

    return 0;
    }
  • 字符串分割所使用方法详解

    • string.c_str()

      c_str()方法的原型如下:

      1
      const _CharT* c_str()

      该方法返回一个指向常量的指针,指针所指向的内容不能被修改,在字符串分割中主要使用该方法将string类型转为char*类型,与字符串分割函数strtok()方法的接收参数类型保持一致。注意:一定要使用strcpy()函数等来操作方法c_str()返回的指针。

    • string.strcpy()

      strcpy()方法的原型如下:

      1
      char * __cdecl strcpy(char * __restrict__ _Dest,const char * __restrict__ _Source);

      该方法将字符串Source复制到Dest。该方法线程不安全,c++提供了线程安全的字符串拷贝方法strcpy_s()。

    • string.strtok()

      strtok()方法的原型如下:

      1
      char *__cdecl strtok(char * __restrict__ _Str,const char * __restrict__ _Delim)

      其中,Str表示要进行分割的字符串,Delim为字符串分隔符,该方法将Delim中的字符作为分隔符对字符串Str进行分割。如果Str为空,则函数内部的SAVE_PTR指针在下一次调用中将作为下一个分割字符串的起始位置。其实这就说明在函数strtok()内部使用了一个静态变量SAVE_PTR指针,用以记录分割一次之后_String中下一个字符串的位置。这种方法导致了一个问题,就是strtok()函数线程不安全的(因为其函数内部使用到了静态存储区)。

      除此之外,从函数的定义,第一个传入参数_String定义为char*而不是const char*,就说明strtok()函数不保证不修改传入数据的内容。实际上,第一个参数_String传进来的字符串,是会被strtok()函数所修改的,因此调用strtok()函数的时候应当注意。

      c++中也提供了线程安全的字符串分割方法strtok_s,其原型如下:

      1
      char *__cdecl strtok_s(char *_Str,const char *_Delim,char **_Context);

      strtok_s()函数增加了一个参数_Context,这个参数就是相当于strtok()函数中内部定义的静态SAVE_PTR指针,用来传递对字符串_String的处理进行到了哪里。

参考文章:C/C++——字符串分割(strtok, strtok_s)