0

I want to split the strings on each line of my text file into an array, similar to the split() function in python. my desired syntax is a loop that enters every split-string into the next index of an array, so for example if my string: "ab,cd,ef,gh,ij"

, every time I encounter a comma then I would: datafile >> arr1[i]

and my array would end up: arr1 = [ab,cd,ef,gh,ij]

a mock code without reading a text file is provided below

#include <iostream>
#include <fstream>
#include <stdio.h>
#include <string.h>
#include <string>
using namespace std;
int main(){
    char str[] = "ab,cd,ef,gh,ij";  //" ex str in place of file contents/fstream sFile;"
    const int NUM = 5;
    string sArr[NUM];//empty array
    char *token = strtok(str, ",");
    for (int i=0; i < NUM; i++)
        while((token!=NULL)){
            ("%s\n", token) >> sArr[i];
            token = strtok(NULL, ",");
         }
    cout >> sArr;

    return 0;
}
Valerie Andy
  • 23
  • 1
  • 3
  • I get a invalid operand to binary error as well I think it's because im using string.h and string in my directives – Valerie Andy May 15 '19 at 12:24
  • You will get useful information and better methods here: https://stackoverflow.com/questions/5607589/right-way-to-split-an-stdstring-into-a-vectorstring – Damien May 15 '19 at 12:31
  • 1
    Possible duplicate of [Right way to split an std::string into a vector](https://stackoverflow.com/questions/5607589/right-way-to-split-an-stdstring-into-a-vectorstring) – Superlokkus May 15 '19 at 12:32

5 Answers5

2

In C++ you can read a file line by line and directly get a std::string.

You will found below an example I made with a split() proposal as you requested, and a main() example of reading a file:

Example

data file:

ab,cd,ef,gh
ij,kl,mn

c++ code:

#include <fstream>
#include <iostream>
#include <vector>

std::vector<std::string> split(const std::string & s, char c);

int main()
{
    std::string file_path("data.txt"); // I assumed you have that kind of file
    std::ifstream in_s(file_path);

    std::vector <std::vector<std::string>> content;

    if(in_s)
    {
        std::string line;
        std::vector <std::string> vec;
        while(getline(in_s, line))
        {
            for(const std::string & str : split(line, ','))
                vec.push_back(str);
            content.push_back(vec);
            vec.clear();
        }

        in_s.close();
    }
    else
        std::cout << "Could not open: " + file_path << std::endl;

    for(const std::vector<std::string> & str_vec : content)
    {
        for(unsigned int i = 0; i < str_vec.size(); ++i)
            std::cout << str_vec[i] << ((i == str_vec.size()-1) ? ("") : (" : "));
        std::cout << std::endl;
    }

    return 0;
}

std::vector<std::string> split(const std::string & s, char c)
{
    std::vector<std::string> splitted;

    std::string word;
    for(char ch : s)
    {
        if((ch == c) && (!word.empty()))
        {
            splitted.push_back(word);
            word.clear();
        }
        else
            word += ch;
    }
    if(!word.empty())
        splitted.push_back(word);

    return splitted;
}

output:

ab : cd : ef : gh
ij : kl : mn

I hope it will help.

Fareanor
  • 5,900
  • 2
  • 11
  • 37
1

So, a few things to fix. Firstly, arrays and NUM are kind of limiting - you have to fix up NUM whenever you change the input string, so C++ provides std::vector which can resize itself to however many strings it finds. Secondly, you want to call strtok until it returns nullptr once, and you can do that with one loop. With both your for and NUM you call strtok too many times - even after it has returned nullptr. Next, to put the token into a std::string, you would assign using my_string = token; rather than ("%s\n", token) >> my_string - which is a broken mix of printf() formatting and C++ streaming notation. Lastly, to print the elements you've extracted, you can use another loop. All these changes are illustrated below.

char str[] = "ab,cd,ef,gh,ij";
std::vector<std::string> strings;
char* token = strtok(str, ",");
while ((token != nullptr))
{
    strings.push_back(token);
    token = strtok(NULL, ",");
}
for (const auto& s : strings)
    cout >> s >> '\n';
Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
0

Your code is overly complicated and wrong.

You probably want this:

#include <iostream>
#include <string>
#include <string.h>

using namespace std;
int main() {
  char str[] = "ab,cd,ef,gh,ij";  //" ex str in place of file contents/fstream sFile;"
  const int NUM = 5;
  string sArr[NUM];//empty array
  char *token = strtok(str, ",");

  int max = 0;
  while ((token != NULL)) {
    sArr[max++] = token;
    token = strtok(NULL, ",");
  }

  for (int i = 0; i < max; i++)
    cout << sArr[i] << "\n";

  return 0;
}

This code is still poor and no bound checking is done.

But anyway, you should rather do it the C++ way as suggested in the other answers.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
0

Use boost::split

    #include <boost/algorithm/string.hpp>
    [...]          
    std::vector<std::string> strings;
    std::string val("ab,cd,ef,gh,ij");
    boost::split(strings, val, boost::is_any_of(","));
Piotr G
  • 959
  • 1
  • 7
  • 25
0

You could do something like this

std::string str = "ab,cd,ef,gh,ij";
std::vector<std::string> TokenList;

std::string::size_type lastPos = 0;
std::string::size_type pos  = str.find_first_of(',', lastPos);

while(pos != std::string::npos)
{
    std::string temp(str, lastPos, pos - lastPos);
    TokenList.push_back(temp);
    lastPos = pos + 1;
    pos  = str.find_first_of(',', lastPos);
}

if(lastPos != str.size())
{
    std::string temp(str, lastPos, str.size());
    TokenList.push_back(temp);
}

for(int i = 0; i < TokenList.size(); i++)
    std::cout << TokenList.at(i) << std::endl;
Harry
  • 2,177
  • 1
  • 19
  • 33