如何通过分隔符将字符串拆分成数组?

15

我是编程新手。我一直在尝试编写一个C++函数,根据给定的参数将字符串的内容拆分成一个字符串数组,例如:

string str = "___this_ is__ th_e str__ing we__ will use__";

应该返回字符串数组:

cout << stringArray[0]; // 'this'
cout << stringArray[1]; // ' is'
cout << stringArray[2]; // ' th'
cout << stringArray[3]; // 'e str'
cout << stringArray[4]; // 'ing we'
cout << stringArray[5]; // ' will use'
我可以将字符串划分成标记,但对我来说最困难的部分是如何在将当前字符串标记分配给它之前指定stringArray中的元素数量,以及如何从函数中返回stringArray。
请有人向我展示如何编写此函数。 编辑1:我不一定需要结果为字符串数组,只要是我可以像常规变量一样调用并具有某种索引方式的任何容器即可。

作业,也许?当然可以,但我属于另一派回答作业问题的人... - dmckee --- ex-moderator kitten
如何在C语言中对字符串进行分词处理? - lothar
@Iothar的回答似乎更高效。 - Arnthor
13个回答

16

我使用向量和字符串来进行首次尝试:

vector<string> explode(const string& str, const char& ch) {
    string next;
    vector<string> result;

    // For each character in the string
    for (string::const_iterator it = str.begin(); it != str.end(); it++) {
        // If we've hit the terminal character
        if (*it == ch) {
            // If we have some characters accumulated
            if (!next.empty()) {
                // Add them to the result vector
                result.push_back(next);
                next.clear();
            }
        } else {
            // Accumulate the next character into the sequence
            next += *it;
        }
    }
    if (!next.empty())
         result.push_back(next);
    return result;
}

希望这能为您提供处理此类问题的思路。在您的示例字符串上,使用以下测试代码返回正确结果:
int main (int, char const **) {
    std::string blah = "___this_ is__ th_e str__ing we__ will use__";
    std::vector<std::string> result = explode(blah, '_');

    for (size_t i = 0; i < result.size(); i++) {
        cout << "\"" << result[i] << "\"" << endl;
    }
    return 0;
}

1
explode() 的第一个参数应该是一个常量引用。编译器会报错,所以“它”需要是一个 string::const_iterator。 - ralphtheninja
1
你应该检查 next 是否为空,如果不为空,则在循环之后将其附加到结果中。否则,分隔符后的最后一个元素将不会被包含在内。 - ddinchev
2
最后一个元素被忽略了!我在下面提供了一个解决方案,它有效! - Ouadie
@Veseliq 我编辑了评论并添加了if语句-一旦我的编辑得到批准,它就会显示出来。 - Natalie Adams

11
使用STL(抱歉没有编译器进行测试)
#include <vector>
#include <string>
#include <sstream>

int main()
{
    std::vector<std::string>   result;

    std::string str = "___this_ is__ th_e str__ing we__ will use__";

    std::stringstream  data(str);

    std::string line;
    while(std::getline(data,line,'_'))
    {
        result.push_back(line); // Note: You may get a couple of blank lines
                                // When multiple underscores are beside each other.
    }
}

// 或者定义一个令牌

#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
#include <sstream>

struct Token: public std::string  // Yes I know this is nasty.
{                                 // But it is just to demosntrate the principle.    
};

std::istream& operator>>(std::istream& s,Token& t)
{
    std::getline(s,t,'_');
   
    // *** 
    // Remove extra '_' characters from the stream.
    char c;
    while(s && ((c = s.get()) != '_')) {/*Do Nothing*/}
    if (s)
    {
        s.unget(); // Put back the last char as it is not '_'
    }
    return s;
}

int main()
{   

    std::string str = "___this_ is__ th_e str__ing we__ will use__";

    std::stringstream  data(str);

    std::vector<std::string>   result(std::istream_iterator<Token>(data),
                                      std::istream_iterator<Token>());
}

因此,在while循环中添加检查以跳过空的“line”行。 - jmucchiello
2
那是用户的练习。 - Martin York

3

它对我有效:

#include <iostream>
#include <vector>
#include <string>

using namespace std;

vector<string> explode( const string &delimiter, const string &explodeme);

int main(int argc, char *argv[])
{
    string str = "I have a lovely bunch of cocoa nuts";
    cout<<str<<endl;
    vector<string> v = explode(" ", str);
    for(int i=0; i<v.size(); i++)
        cout <<i << " ["<< v[i] <<"] " <<endl;
}

vector<string> explode( const string &delimiter, const string &str)
{
    vector<string> arr;

    int strleng = str.length();
    int delleng = delimiter.length();
    if (delleng==0)
        return arr;//no change

    int i=0;
    int k=0;
    while( i<strleng )
    {
        int j=0;
        while (i+j<strleng && j<delleng && str[i+j]==delimiter[j])
            j++;
        if (j==delleng)//found delimiter
        {
            arr.push_back(  str.substr(k, i-k) );
            i+=delleng;
            k=i;
        }
        else
        {
            i++;
        }
    }
    arr.push_back(  str.substr(k, i-k) );
    return arr;
}

来源 : http://www.zedwood.com/article/106/cpp-explode-function

这是一篇关于C++中explode函数的文章。explode函数可以将字符串按照指定分隔符进行拆分,并返回一个包含拆分后子串的数组。本文介绍了explode函数的实现方法和使用示例,希望对C++开发者有所帮助。

1

如果你坚持将 stringArray 定义为数组而不是 std::vector<>(后者才是正确的做法),那么你必须要么:

  1. 进行两次遍历(一次用于计数)
  2. 自己实现动态数组。

使用 vector 更容易,vector::push_back() 可以将新内容附加到末尾。所以:

vector* explode(string s){
  vector<string> *v = new vector<string>
  //...
  // in a loop
    v->push_back(string_fragment);
  //...
  return v;
}

实际上不需要为了完整性而保留。

要返回字符串数组,您可以使用char **

例如:

char ** explode(const char *in){
  ...

}

顺便提一下-- 调用函数如何知道返回的数组有多少元素?你也必须解决这个问题。除非受到外部限制,否则使用std :: vector<>...


v->push_back(string_fragment); -> v->push_back(string_fragment); - ralphtheninja
我认为传递一个堆栈分配的向量返回,或者使用向量引用进行填充比在函数中分配原始向量,然后将删除责任传递给客户端更好。 - GManNickG
@GMan:也许你是对的。我在翻译时仍然使用C++,并保留了很多C语言的习惯... - dmckee --- ex-moderator kitten

1
你可以使用字符串向量 (std::vector<std::string>),通过 push_back 将每个标记附加到其中,然后从 tokenize 函数中返回它。

1
使用std::vector作为动态数组,并将其作为结果返回。

1
也许你应该使用列表而不是数组。这样你就不需要提前知道元素的数量了。你还可以考虑使用STL容器。

0

我认为我写了一个更简单的解决方案。

std::vector<std::string> explode(const std::string& string, const char delimiter) {

std::vector<std::string> result;
unsigned int start = 0, pos = 0;

while (pos != string.length()) {
    if (string.at(pos) == delimiter || pos + 1 == string.length()) {
        unsigned int size = (pos - start) + ((pos + 1) == string.length() ? 1 : 0);
        if (size != 0) { // Make this 'if' as a option? like a parameter with removeEmptyString?
            result.push_back(string.substr(start, size));
        }
        start = pos + 1;
    }
    pos++;
}

return std::move(result);

}


0

以下是代码:

template <typename OutputIterator>
int explode(const string &s, const char c, OutputIterator output) {
    stringstream  data(s);
    string line;
    int i=0;
    while(std::getline(data,line,c)) { *output++ = line; i++; }
    return i;
}

int main(...) {
  string test="H:AMBV4:2:182.45:182.45:182.45:182.45:182.41:32:17700:3229365:201008121711:0";
  cout << test << endl; 
  vector<string> event;
**This is the main call**
  int evts = explode(test,':', back_inserter(event));
  for (int k=0; k<evts; k++) 
    cout << event[k] << "~";
  cout << endl;
}

输出

H:AMBV4:2:182.45:182.45:182.45:182.45:182.41:32:17700:3229365:201008121711:0
H~AMBV4~2~182.45~182.45~182.45~182.45~182.41~32~17700~3229365~201008121711~0~

0

这是我编写的代码(完整版)。也许对于有相同需求的人来说会有用。

#include <string>
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;

int main(){
        std::string s = "scott:tiger:mushroom";
        std::string delimiter = ":";

        std::vector<std::string> outputArr;
        size_t pos = 0;
        std::string token;
        while ((pos = s.find(delimiter)) != std::string::npos) {
            token = s.substr(0, pos);
            s.erase(0, pos + delimiter.length());
            outputArr.push_back(token);
        }
        outputArr.push_back(s);

        // Printing Array to see the results
        std::cout<<"====================================================================================\n";
        for ( int i=0;i<outputArr.size();i++){
                std::cout<<outputArr[i]<<"\n";
        }
        std::cout<<"====================================================================================\n";
}

干杯!!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接