Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

String splitter; is there a better way of doing this?

Status
Not open for further replies.

scimatic

Technical User
Aug 30, 2004
19
US
What I want to do is read a string with a bunch of words seperated by a delimiter, in this case the delimiter is a tilda ('~'). The number of words in the string i want to split is always unknown. I want to store the words in a structure where I can print out each word using a for loop like I have in my code. This program runs just the way I want it to, i'm just wondering if anyone could tell me a better way of doing it. I would like to avoid allocating more memory then I have to.

Thanks

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main()
{
// d1 and d2 are used to track the delimiter
int d1 = 0, d2 = 0, i = 0;

// here is the string with '~' as the delimiter
string line = "ID~ARCHIVE~AREA~CASEBOX~CHAR~CIPOCONF";

// for loop to count number of delimiters in string
for(int t=0; t<= line.length(); t++)
if(line[t] == '~')
i++;

// set the # of elements for string array based on for loop above
string* fields = new string[i+1];

// reset i to 0 for the while loop
i = 0;

// while loop creates and assigns substring to array based
// on location of the delimiter
while(line.find("~",d1)!= string::npos)
{
d2 = line.find("~",d1);
fields = line.substr(d1,d2-d1);
d1 = d2;d1++;i++;
}

// puts the last element of the string in array
fields = line.substr(d1,line.length());

// prints the seperated words
for(t = 0; t <= i; t++)
{
cout << fields[t] << endl;
}

return 0;
}
 
Please use [ignore]
Code:
[/ignore]
code tags

--
 
I'd use a vector to store the strings because it's a lot easier than using an array, and I really wouldn't worry too much about dynamically allocating, your computer can handle it fine if execution speed isn't a problem. BTW, don't forget to delete [] fields when you're done with it.
 
And in oldtimer style:

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

int main()
{
char line[] = "ID~ARCHIVE~AREA~CASEBOX~CHAR~CIPOCONF";
int line_len;
char *buf=NULL;
char *buf_ptr;
int field_cnt=0;
char **fields=NULL;
int ii;

   line_len=strlen(line);

   buf=new char[line_len+1];
   if(buf)
   {   
      strcpy(buf, line);
 
      buf_ptr=buf;
      while(*buf_ptr) if((*buf_ptr++)=='~') field_cnt++;

      fields = new char* [field_cnt+1];
      
      if(fields)
      {
         buf_ptr=buf;
         ii = 0;
         fields[ii++]=buf_ptr;
         while(*buf_ptr)
         {
            if((*buf_ptr)=='~')
            {
               *(buf_ptr++)=0;
               fields[ii++]=buf_ptr;
            }
            else buf_ptr++;
         }
 
         for(ii = 0; ii <= field_cnt; ii++)
            cout << fields[ii] << endl;
 
         delete [] fields;
      }
   
      delete [] buf;
   }

return(0);
}
 
How about:
Code:
int main()
{
  Tokens t;
  t.split("ID~ARCHIVE~AREA~CASEBOX~CHAR~CIPOCONF");
  for (int i = 0; i < t.size(); ++i)
      cout << t[i] << endl;
  return 0;
}
impromptu:
Code:
class Tokens
{
public:
  Tokens(const char* str = 0);
  virtual ~Tokens();
  int split(const char* str);
  int split(const string& s) { return split(s.c_str()); }
  int size() const { return n; }
  const char* operator [](int i) const 
  { 
    return i >= 0 && i < n?pp[i]:0; 
  }
  void reset();
  char setSep(char ch);
protected:
  int expand(int delta = 8);
  char seps[4];
  char** pp;
  int bsz;
  char*  buf;
  int n;
private:
  Tokens(const Tokens&);
  Tokens& operator=(const Tokens&);
};

// Implementation (w/o STL):
#include <cstring>
Tokens::Tokens(const char* str):n(0), buf(0), bsz(0), pp(0)
{
  memcpy(seps,"~ \t",4);
  split(str);
}

void Tokens::reset()
{
  delete [] pp;
  bsz = 0;
  delete [] buf;
  n = 0;
}

Tokens::~Tokens()
{
  reset();
}

int Tokens::expand(int delta)
{
  int newn = bsz + delta;
  char** p = new char*[newn];
  for (int i = 0; i < n; ++i)
      p[i] = pp[i];
  delete [] pp;
  pp = p;
  return bsz = newn;
}

char Tokens::setSep(char ch)
{
  char chold = seps[0];
  if (ch)
     seps[0] = ch;
  return chold;
}

int Tokens::split(const char* str)
{
  reset();
  if (str)
  {
    int sz = strlen(str) + 1;
    buf = new char[sz];
    memcpy(buf,str,sz);
    char* p = strtok(buf,seps);
    for (n = 0; p; ++n)
    {
      if (n >= bsz)
         expand();
      pp[n] = p;
      p = strtok(0,seps);
    }
  }
  return n;
}
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top