strcat issue

Hi expert, I am asking a lot questions. Here is the new one regarding strcat.
I want to strcat the "-" to the third column first, then strcat the second column to the third column.

here is my code, no compiling error, but results are funny. Whats wrong with my code ? Thank you

                                                                         ...
                                                char *token = MyStrTok( row_read,',' );

                  while( token != NULL )
                  {
                              // append "-" to 3rd column
                              if (i == 2)
                              {
                                    char tmp3[500];
                                    strcpy(tmp3,token);
                                    strcat(tmp3,"-");                  // strcat "-" to tmp3
                                    cout << tmp3 << endl;        << i have funny result here
                                    
                              }
                                                                                            // append 2nd column to 3rd column
                               else if (i == 1)
                               {
                                     char tmp2[500];
                                     strcpy (tmp2,token);
                                     strcat (tmp3,tmp2);
                                    cout << tmp3 << endl;      << i have funny result here                        
                                     strcpy (row_elem[3],tmp3);
                               }
                               else
                               {
                                    strcpy(row_elem[i], token );
                                    //strcpy(row_elem[i], tmp2 );
                               }      
                                          //* Get next token: */
                                    token = MyStrTok( NULL, ',' );
                                    i++;
                              
                                    //cout << token << endl;
                  }
      
justinYAsked:
Who is Participating?
 
drichardsConnect With a Mentor Commented:
The runtime errors on the substr calls are in the lines that have an empty field.  You can do substr(0,n) on an empty string because there's always the null termination.  If index is >0 it fails.  The other errors are because you need to do 'part1.c_str()' to an output stream.  As for leaving the empty spaces when the field value is blank, you could use code like this:

string part1;
string part2;
string part3;
if ( row_elem[4].length() > 4 )
{
   part1 = row_elem[4].substr(0,2);
   part2 = row_elem[4].substr(2,2);
   part3 = row_elem[4].substr(4,1);
}

Then:

      fout<< setw(10) << part1.c_str()
           << setw(10) << part2.c_str()
           << setw(10) << part3.c_str()
            <<endl;

Remember, you cannot use a std::string in place of char* (really const char*).  You need to use string.c_str() to get a const char* that will work with the streams.
0
 
drichardsCommented:
Where is the value of 'i' being set?  Also, your logic seems incorrect.  You need to save the value of column 2 somewhere until you read column 3.  Then you can addpend the '-' and the column 2 string to column 3 when you read column 3.  I assume 'i' is the 0-based column number?
0
 
drichardsCommented:
Also, what is the "funny" result?  The strcat lines are correct, it is the parameters that seem to be the problem.

And what is row_elem?  If you are concatenating columns 2/3 into a single string, it seems that 'i' needs to skip an increment somewhere in there.
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
justinYAuthor Commented:
Hi drichards, thank you very much for my last question. Your solution works really well. Its hard to see you here. So i am going to use all my day to get as much as i can from you.
Back to this question,
I set the value of 'i' in if ( i ==2 ) and if ( i ==3 ). So, I change my code here:
                           if (i == 1)
                         {
                              char tmp2[500];
                              char tmpsave[500];
                              strcpy(tmp2,token);
                              strcpy(tmpsave,tmp2);          // save tmp2 in tmpsave
                          }
                           else if ( i == 2)
                          {
                              char tmp3[500];
                              strcopy(tmp3,token);
                              strcat(tmp3,"-");
                              strcat(tmp3,tmpsave)         // Is this right ? Thank you
                           }
                             
0
 
drichardsCommented:
You don't need to copy into the temporary tmp2 when i==1.  You need to make sure row_elem gets updated properly as well.  It's not clear what your intention is.

Also, you could use a variation of the GetField method from the other question:

int GetFields(std::string &aStr, std::vector<string> &aVec, char aDelim)
{
    std::istringstream ss(aStr);
    std::string field;
    while (std::getline(ss, field, aDelim))
    {
        aVec.push_back(field);
    }
    return aVec.size();
}

This will fill a vector with all the tokens in one shot.  Then you can just do some simple logic like:

        std::string line(row_read);
        std::vector<string> fields;
        int numFields = GetFields(line, fields, ',');
        fields[2] += "-";
        fields[2] += fields[1];
        std::vector<string>::iterator iter = fields.begin();
        iter++;    // move to second column
        fields.erase(iter); // erase the 2nd column that was appended to column 3

If I read your code correctly, fields should be equivaent to your row_elem array (except that fields is a std::vector of strings).  Or did you mean to hav row_elem contain all the original tokens/fields, in which case you should replace fields[2] += ... with:

    std::string combo = fields[2];
    combo += "-";
    combo += fields[1];

and leave the fields vector alone (no erasing).
0
 
justinYAuthor Commented:
This is not working neither.

row_elem[i] is the fields of the row. So baciscally I want to strcat 3rd column to 2nd column. between them I have a '-'. like nnnnnnnn-mmmmmm.

No compiling errors, but when cout << tmp3 << endl; it displays strange character and never stops. it just runs and runs.
Whats wrong ?
0
 
drichardsCommented:
Only problem I see is that tmpsave needs to be declared outside the 'while( token != NULL )' loop so it doesn't go out of scope and lose its value between iterations.  It's giving you a bad strcat call in the i==2 case.  You can also eliminate tmp2 if you haven't already.

I'd still recommend looking at the GetFields function as it gives you row_elem directly.
0
 
justinYAuthor Commented:
drichards,
I am more interested in your GetFields function.
But I have compiling errors at

int GetFields(std::string &aStr, std::vector<string> &aVec, char aDelim)
{
    std::istringstream ss(aStr);                                                << cannot convert from 'std::string' to int
    std::string field;
    while (std::getline(ss, field, aDelim))                                   << and errors here
    {
        aVec.push_back(field);
    }
    return aVec.size();
}

I have #include <vector> also.
0
 
justinYAuthor Commented:
Hi again, the only reason i use row_elem[i] is that I need to do
fout << setw(10) << row_elem[0]
       << setw(10)<<row_elem[2]
       << setw(10)<<row_elem[3}
         ....
       <<setw(10)<< row_elem[20]
       <<endl;

If GetFields function can do the same thing, I will be more than happy to use it.
                                                                                         
0
 
drichardsCommented:
Need to #include <sstream> as well
0
 
drichardsCommented:
everywhere you see 'row_elem[n]', substitute 'fields[n].c_str()', assuming the vector is called fields.  If you name the vector 'row_elem', just add '.c_str()':

fout << setw(10) << row_elem[0].c_str()  // or 'fields[0].c_str()' if the vector is named 'fields' as in my sample code.
       << setw(10)<<row_elem[2].c_str()
       << setw(10)<<row_elem[3].c_str()
         ....
       <<setw(10)<< row_elem[20].c_str()
       <<endl;
0
 
justinYAuthor Commented:
I am using GetFields function to rewrite my program, so I can truely understand it. My main frame is the followings:
my input file
transaction id,notes1,notes2,notes3,account name,amount,trade date,load amount
="111",="aaa",aaaaaaaa3,a4,,100000,1/1/2004,0
="222",="bbb",bbbbbbbb3,b4,,200000,1/15/2004,0
="333",="ccc",cccccccc3,c4,cccc5,300000,1/15/2004,888
="444",="ddd",dddddddd3,d4,dddd5,400000,1/15/2004,-998
="555",="eee",eeeeeeee3,e4,eeee5,500000,1/15/2004,9800
="666",="fff",ffffffff3,f4,ffff5,600000,1/15/2004,0
="777",="ggg",gggggggg3,g4,gggg5,700000,1/15/2004,-7654
="888",="hhh",hhhhhhhh3,h4,hhhh5,800000,1/15/2004,99
="999",="iii",iiiiiiii3,i4,iiii5,900000,1/15/2004,-7877

my code:

#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <sstream>

using namespace std;

int GetFields(std::string &aStr, std::vector<string> &aVec, char aDelim)
{
std::istringstream ss(aStr);
std::string field;
while (std::getline(ss, field, aDelim))
{
aVec.push_back(field);
}
return aVec.size();
};

string removechars( string st, string delim )
{
    string result = "";

    for( unsigned int x = 0; x < st.length(); x++ )
    {
         if( delim.find_first_of( st[x] ) == delim.npos )
             result += st[x];
}
    return result;
};

void DateConvert(char* date)
{
int day, month, year;
if ( sscanf ( date, "%d/%d/%d", &month, &day, &year ) == 3 );
sprintf(date, "%02d%02d%04d", month, day, year );
};

main(int arc, char *arv[])
{
      ifstream fin("fin.txt");
      ofstream fout("fout.txt");
      char row_read[512];
      char row_elem[50][50];
      int i=0;
      string str;
      int day, month, year;
      char date[50];
while (fin.getline(row_read, sizeof(row_read))
{
std::string line(row_read);
std::vector<string> fields; // vector called fileds
int numFields = GetFields(line, fields, ',');
fields[2] += "-";
fields[2] += fields[1];
std::vector<string>::iterator iter = fields.begin();
iter++; // move to second column
fields.erase(iter); // erase the 2nd column that was appended to column 3
cout<<fileds[2].c_str()<<endl;

}
}

I have compiling errors, whats wrong ?
0
 
drichardsCommented:
I fixed the errors and changed the code slightly.  Here are the changes...

void DateConvert(char* date)
{
    int day, month, year;
    if ( sscanf ( date, "%d/%d/%d", &month, &day, &year ) == 3 ); // do you really need 'if ...'.  Gives compiler warning.
    sprintf(date, "%02d%02d%04d", month, day, year );
};

main(int arc, char *arv[])
{
    ifstream fin("D:\\DevProjects\\CPPConsole\\fin.txt");
     ofstream fout("fout.txt");
//     char row_elem[50][50];
     int i=0;
     string row_read; // use std::string
//     int day, month, year;
//     char date[50];

     while (std::getline(fin,row_read)) // use std::getline
    {
    std::vector<string> fields; // vector called fileds
    size_t numFields = GetFields(row_read, fields, ',');
    fields[2] += "-";
    fields[2] += fields[1];
    std::vector<string>::iterator iter = fields.begin();
    iter++; // move to second column
    fields.erase(iter); // erase the 2nd column that was appended to column 3
    cout<<fields[1].c_str()<<endl; // old column 2 was erased.

    }
}
0
 
justinYAuthor Commented:
Thanks, It works very well. wow, what a productive day ! I will fill in my stuff to rewrite my code by using GetFields. How late u still here ? I might run into some problems.
0
 
drichardsCommented:
I'll be around for e few hours yet.
0
 
justinYAuthor Commented:
I have trouble to plug in my two functions below. I dont know which parameter i need pass into the functions

string removechars( string st, string delim )
{
    string result = "";

    for( unsigned int x = 0; x < st.length(); x++ )
    {
         if( delim.find_first_of( st[x] ) == delim.npos )
             result += st[x];
}
    return result;
};

void DateConvert(char* date)
{
int day, month, year;
if ( sscanf ( date, "%d/%d/%d", &month, &day, &year ) == 3 );
sprintf(date, "%02d%02d%04d", month, day, year );
};
0
 
drichardsCommented:
In DateConvert and removechars, are you trying to modify the original string or get a new one?  Or do you want the option of either?
0
 
justinYAuthor Commented:
I want both, and I am trying to modify the original string, after that my string are clean, then i can do MyStrTok, fields and cout << 
0
 
justinYAuthor Commented:
we are using fileds to replace row_elem, so are we using line to replace row_read ?
0
 
drichardsCommented:
>> we are using fileds to replace row_elem, so are we using line to replace row_read
Yes.  You can always rename fields and line back to row_elem and row_read so it looks more the same.

And here's 'removechars'.  It returns a new string.  You can replace the original string like this:  'original = removechars(original, "/0");'.  If original was "1/1/2004", the result would be "1124" as the '/' and '0' characters would be removed from the string.  I'm looking at DateConvert.

----------------------------------------------------------------------
string removechars( string &st, string delim )
{
    string result = "";

    size_t npos1 = 0, npos2 = 0;
    while ((npos2 = st.find_first_of(delim, npos1)) < st.length())
    {
        result += st.substr(npos1, (npos2-npos1));
        npos1 = npos2 + 1;
    }
    result += st.substr(npos1);
    return result;
};
0
 
justinYAuthor Commented:
I am heading home now. I will be here tonight and tomorrow morning. Will you be here tomorrow ? what time? I am in US Eastern Time Zone, where r u?
If I dont see you, have a great weekend ! Thanks again
0
 
drichardsCommented:
I'm Central time, and yes, I'll be hanging around my computer over the weekend.
0
 
drichardsCommented:
Here's a version of DateConvert that modifies the input string (like your original did):
-----------------------------
void DateConvert(string &date)
{
    int day, month, year;
    if ( sscanf ( date.c_str(), "%d/%d/%d", &month, &day, &year ) == 3 )
    {
        char newdate[32];
        sprintf(newdate, "%02d%02d%04d", month, day, year );
        date = newdate;
    }
};
--------------------------------

Here's one that doesn't:
-------------------------------------------
string DateConvert(string &date)
{
    int day, month, year;
    string result;
    if ( sscanf ( date.c_str(), "%d/%d/%d", &month, &day, &year ) == 3 )
    {
        char newdate[32];
        sprintf(newdate, "%02d%02d%04d", month, day, year );
        result = newdate;
    }
    else
    {
        result = date;
    }
    return result;
};
0
 
justinYAuthor Commented:
I plug GetFields function into my program.  and i have compiling error : 'GetFields' : cannot convert parameter 1 from 'char [512]' to 'std::string &'
Whats wrong ?

my purposes in this program are:

1.skip first line
2. remove unwanted characters
3. convert date format
4. strcat row_elem[1] to row_elem[2]
5. extract substring from row_elem[4] and chop it into 3 pieces by positions(e.g. substring1 position 1-2, substring2 position 2-3, substring3 position 3-4)

main(int arc, char *arv[])
{

      ifstream fin("fin.txt");
      ofstream fout("fout.txt");
      char row_read[512];
      char row_elem[50][50];

      ifstream fin2("frefer.csv");
      ofstream fout2("refer_out.txt");
      KeyRef refer_data[MaxSize];
      char refer_read[MaxSize];
      char refer_row_elem[2][MaxSize];
      int i=0,j=0,k=0;

      int isFirstLine = 0;

///////////////////////////////////////////////////////////////////
// for each line of file  
// assume there are 7 columns in each row in file fin.txt
///////////////////////////////////////////////////////////////////

while( fin.getline( row_read, sizeof( row_read ) ) )
{
      //////////////////////////////////////////
      // skip first line
      //////////////////////////////////////////
      if( isFirstLine == 0)
      {
                  //isFirstLine = false;
                  isFirstLine = 1;
                  continue ;
      }

      //////////////////////////////////////////
      // get tokens, parse string with ","
      //////////////////////////////////////////
      char *token = MyStrTok( row_read, ',' );

      while( token != NULL )
      {

                                 ///////////////////////////////////////////////////////////
            // strim '"', '=' etc.. in the fields
            //////////////////////////////////////////////////////////
             char intrBuf[MaxSize];
             strcpy(intrBuf,token);
             removeChar(intrBuf,'=');      
             removeChar(intrBuf,'"');

            /////////////////////////////////////////////////////////////
            //write the tokens into row_elem[i]
            ////////////////////////////////////////////////////////////
            //cout << i <<  " after strim <" << intrBuf << ">" <<  endl;

            ////////////////////////////////////
            // skip blank column
            ////////////////////////////////////
            if (token[0] == '\0') {
                  //cout << "Blank field found - " << i << endl;
                         strcpy(row_elem[i], " ");
            }
            else {
            
                  ////////////////////////////////
                  // convert date field
                  ////////////////////////////////
                  if (i == 9) {
                              DateConvert(intrBuf);
                               strcpy(row_elem[i], intrBuf);
                  }
                  else
                               strcpy(row_elem[i], intrBuf );

//////////////////////////////////////////////////////////////////////////////////
// strcat row_elem[1] to row_elem[2]
// plug in GetFields function here, and compiling errors
/////////////////////////////////////////////////////////////////////////////////

std::vector<string> row_elem; // vector called fileds
    size_t numFields = GetFields(row_read, row_elem, ',');
    row_elem[2] += "-";
    row_elem[2] += row_elem[1];
    std::vector<string>::iterator iter = row_elem.begin();
    iter++;
//cout<<row_elem[2].c_str()<<endl;


            }

                   /* Get next token: */
                   token = MyStrTok( NULL, ',' );
                   i++;
       } //end of while
}
0
 
drichardsCommented:
A couple of things:

1) You don't need MyStrTok any more - it is replaced by GetFields which does the whole job at once.

2) I made a subtle change to GetFields to take a string& instead of a string as first parameter.  This means you need to pass a string, not a char*.  If you use std::getline to read the file (since you don't need to use MyStrTok any more this is OK.

I'll show you what I mean - give me a few minutes.
0
 
drichardsCommented:
One question for you.  You have logivc in your while (token) loop that says 'if (i == 9)' yet you never set i back to 0 at any point.  Are you really stuffing tokens into row_elem in a big long string, or is row_elem just based on a single row of the file and i should be reset for each new line?
0
 
drichardsCommented:
OK, another question.  Does the combined col3/col2 string go into row_elem or do the two strings go in separately?
0
 
drichardsCommented:
OK, here's a version of your code that assumes row_elem is an array for each line only.  It can easily modified to make row_elem running storage for all the tokens.  It's not clear what you're doing with row_elem in the end.  Also, this version does NOT append col2 to col3 because that was another question I had.  Also, with the 'if (ii==9)', the comment at the top of the program says there are 7 columns, so how can ii ever be 9?
----------------------------------------------------------------------------------
string removechars( string &st, string delim )
{
    string result = "";

    size_t npos1 = 0, npos2 = 0;
    while ((npos2 = st.find_first_of(delim, npos1)) < st.length())
    {
        result += st.substr(npos1, (npos2-npos1));
        npos1 = npos2 + 1;
    }
    result += st.substr(npos1);
    return result;
};

void DateConvert(string &date)
{
    int day, month, year;
    if ( sscanf ( date.c_str(), "%d/%d/%d", &month, &day, &year ) == 3 )
    {
        char newdate[32];
        sprintf(newdate, "%02d%02d%04d", month, day, year );
        date = newdate;
    }
};

main(int arc, char *arv[])
{
    ifstream fin("fin.txt");
    ofstream fout("fout.txt");
    string row_read;

    ifstream fin2("frefer.csv");
    ofstream fout2("refer_out.txt");
//    KeyRef refer_data[MaxSize];
//    char refer_read[MaxSize];
//    char refer_row_elem[2][MaxSize];
//    int j=0,k=0;

///////////////////////////////////////////////////////////////////
// for each line of file  
// assume there are 7 columns in each row in file fin.txt
///////////////////////////////////////////////////////////////////
//////////////////////////////////////////
// skip first line
//////////////////////////////////////////
    std::getline(fin, row_read);

    while( std::getline(fin, row_read) )
    {

        //////////////////////////////////////////
        // get tokens into row_elem, parse string with ","
        //////////////////////////////////////////
        vector<string> row_elem;
        GetFields(row_read, row_elem, ',');

        for ( unsigned ii = 0; ii < row_elem.size(); ii++ )
        {
            string &curStr = row_elem[ii];
            ///////////////////////////////////////////////////////////
            // remove '"', '=' in the fields
            //////////////////////////////////////////////////////////
            curStr = removechars(curStr, "\"=");

            ////////////////////////////////////
            // put space in empty columns
            ////////////////////////////////////
            if (curStr.empty()) {
                curStr = " ";
            }

            ////////////////////////////////
            // convert date field
            ////////////////////////////////
            if (ii == 9)                             // Only 7 columns according to comment at start?????
            {
                DateConvert(curStr);
            }
        } //end of while
    }
}
0
 
justinYAuthor Commented:
answer your questions:
1. row_elem is based on a single row of the file. It reads row by row
2. combined col3/col2 go into row_elem, so i can do fout<<setw(10)<<row_elem[3]

Also, let me give you my whole code. thats my whole picture

input file
transaction id,notes1,notes2,notes3,account name,amount,trade date,load amount
="111",="aaa",aaaaaaaa3,a4,,100000,1/1/2004,0
="222",="bbb",bbbbbbbb3,b4,,200000,1/15/2004,0
="333",="ccc",cccccccc3,c4,cccc5,300000,1/15/2004,888
="444",="ddd",dddddddd3,d4,dddd5,400000,1/15/2004,-998
="555",="eee",eeeeeeee3,e4,eeee5,500000,1/15/2004,9800
="666",="fff",ffffffff3,f4,ffff5,600000,1/15/2004,0
="777",="ggg",gggggggg3,g4,gggg5,700000,1/15/2004,-7654
="888",="hhh",hhhhhhhh3,h4,hhhh5,800000,1/15/2004,99
="999",="iii",iiiiiiii3,i4,iiii5,900000,1/15/2004,-7877


frefer file
111,111aaa
222,222bbb
333,333ccc
444,444ddd
555,555eee
666,666fff
777,777ggg
888,888hhh
999,999iii

my purposes in this program are:

0.I have 2 files: fin and frefer. frefer is a reference file. i need return a frefer column
1.skip first line
2. remove unwanted characters
3. convert date format
4. strcat row_elem[1] to row_elem[2]
5. extract substring from row_elem[4] and chop it into 3 pieces by positions(e.g. substring1 position 1-2, substring2 position 2-3, substring3 position 3-4)


#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <stdlib.h>
#include <stdio.h>
#include <vector>
#include <sstream>


using namespace std;

const int MaxSize=1024;


int GetFields(std::string &aStr, std::vector<string> &aVec, char aDelim)
{
std::istringstream ss(aStr);
std::string field;
while (std::getline(ss, field, aDelim))
{
aVec.push_back(field);
}
return aVec.size();
};

///////////////////////////////////////////////////////////////////////
// convert date formate from mm/dd/yyyy to mmddyyyy
//////////////////////////////////////////////////////////////////////
void DateConvert(char* date)
{
int day, month, year;
//if ( sscanf ( date, "%d/%d/%d", &month, &day, &year ) == 3 );
sscanf ( date, "%d/%d/%d", &month, &day, &year ) == 3 ;
sprintf(date, "%02d%02d%04d", month, day, year );
};

//////////////////////////////////
// struct for reference data
//////////////////////////////////
typedef struct
{             char keyData[100];
            char valueData[100];
}KeyRef;


//////////////////////////////////////////
// function to lookup value by key
//////////////////////////////////////////
char* findKeyValue(KeyRef* ref, char* k){
   
     for (int i=0;i<MaxSize;i++){
          if (!strcmp(ref[i].keyData,k))
               return ref[i].valueData;
     }
    return "None";
            
};

//////////////////////////////////////////
// Remove delimiter  
//////////////////////////////////////////
void removeChar(char* src, char delim ) {
      int i=0,j=0;
      char buf[MaxSize];
      while (src[i] != '\0' ) {
            if (src[i] == delim){
                  i++;
                  continue;
            }
            buf[j++]=src[i];
            i++;
      }
      buf[j] = '\0';
      strcpy(src,buf);
};


////////////////////////////////////////////////////////////
// Custom version of strtok(), fixing empty field problem
////////////////////////////////////////////////////////////
char* MyStrTok(char* text, const char del)
{
    static char *curTok = NULL;
    char *result = NULL;
    if ( text != NULL )
    {
        curTok = text;
    }
    result = curTok;
    if ( curTok != NULL )
    {
        //curTok = ::strchr(curTok, del);
        curTok = strchr(curTok, del);

        if ( curTok != NULL ) *curTok++ = 0;
    }
    return result;
};


///////////////////////////////
//
// main
//
///////////////////////////////
main(int arc, char *arv[])
{

      ifstream fin("fin.txt");
      ofstream fout("fout.txt");
      char row_read[512];
      char row_elem[50][50];

      ifstream fin2("frefer.csv");
      ofstream fout2("refer_out.txt");
      KeyRef refer_data[MaxSize];
      char refer_read[MaxSize];
      char refer_row_elem[2][MaxSize];
      int i=0,j=0,k=0;

      int isFirstLine = 0;

//////////////////////////////////////////
// read refer file into struct of array
//////////////////////////////////////////
while( fin2.getline( refer_read,MaxSize ))
{
                 /////////////////////////////////////////////////
      // skip first line of reference file " frefer
      /////////////////////////////////////////////////
     if( isFirstLine == 0)
     {
            isFirstLine = 1;
     }
     else {

       char *tok = MyStrTok(refer_read,',');
           while( tok != NULL) {
          strcpy(refer_row_elem[j],tok);

          tok= MyStrTok(NULL,',');
          j++;
           }
           strcpy(refer_data[k].keyData, refer_row_elem[0]);
           strcpy(refer_data[k].valueData, refer_row_elem[1]);
           j=0;
           k++;
     }
      
}

/////////////////////////////////////////////////
// output refer file , review data only
/////////////////////////////////////////////////
//for (int q=0;q<k;q++){
//      fout2 << setw(10) << refer_data[q].keyData << setw(10) << refer_data[q].valueData << endl;
//}


///////////////////////////////////////////////////////////////////
// for each line of file  
// assume there are 5 columns in each row in file fin.txt
///////////////////////////////////////////////////////////////////
isFirstLine=0;

while( fin.getline( row_read, sizeof( row_read ) ) )
{
      //////////////////////////////////////////
      // skip first line
      //////////////////////////////////////////
      if( isFirstLine == 0)
      {
                  //isFirstLine = false;
                  isFirstLine = 1;
                  continue ;
      }

      //////////////////////////////////////////
      // get tokens, parse string with ","
      //////////////////////////////////////////
      char *token = MyStrTok( row_read, ',' );

      while( token != NULL )
      {

        ///////////////////////////////////////////////////////////
            // strim '"', '=' etc.. in the fields
            //////////////////////////////////////////////////////////
             char intrBuf[MaxSize];
             strcpy(intrBuf,token);
             removeChar(intrBuf,'=');      
             removeChar(intrBuf,'"');

            /////////////////////////////////////////////////////////////
            //write the tokens into row_elem[i]
            ////////////////////////////////////////////////////////////
            //cout << i <<  " after strim <" << intrBuf << ">" <<  endl;

            ////////////////////////////////////
            // skip blank column
            ////////////////////////////////////
            if (token[0] == '\0') {
                  //cout << "Blank field found - " << i << endl;
                         strcpy(row_elem[i], " ");
            }
            else {
            
                  ////////////////////////////////
                  // convert date field
                  ////////////////////////////////
                  if (i == 9) {
                              DateConvert(intrBuf);
                               strcpy(row_elem[i], intrBuf);
                  }
                  else
                               strcpy(row_elem[i], intrBuf );
                  }

                   /* Get next token: */
                   token = MyStrTok( NULL, ',' );
                   i++;
       } //end of while

     //////////////////////////////////////////////////////////////////////
     // get reference value by looking at key in reference file
     //////////////////////////////////////////////////////////////////////
     char* valueFound;
     valueFound = findKeyValue(refer_data, row_elem[0]);
     //cout << " value found - " << valueFound << endl;

     //////////////////////////////////////////////////////////////////////
     // output to file, first colmn replaced with value from reference file
     //////////////////////////////////////////////////////////////////////

                           fout<<setw(5)      << row_elem[0]
            <<setw(2)            << " "
            <<setw(5)            << row_elem[1]
            <<setw(2)            << " "
            <<setw(5)            << row_elem[2]
            <<setw(2)            << " "
            <<setw(9)            << valueFound
            <<setw(2)            << " "
            <<setw(5)            << row_elem[3]
            <<setw(2)            << " "
            <<setw(10)            << row_elem[4]
            <<setw(2)            << " "
            <<setw(10)            << row_elem[5]
            <<setw(2)            << " "
            <<setw(10)            << row_elem[6]
            <<setw(2)            << " "
            <<setw(10)            << row_elem[7]
            <<setw(2)            << " "
            <<setw(1)            << "S"
            << endl;

            
     i=0;

}

//cout << "End." << endl;
return 0;

}
0
 
justinYAuthor Commented:
right, i should be 6 to convert the date format
0
 
drichardsCommented:
OK, based on your answers, you can change the 9 to a 6 and then when the line processing is done (at the bottom of the 'while (std::getline...)' loop) you can combine the columns and remove the extra one from row_elem if you don't want to keep it.  Otherwise, the code I gave you I believe does what you are looking for.
0
 
justinYAuthor Commented:
thanks, i am trying to put them together now.


0
 
justinYAuthor Commented:
your code working very well.
I am trying to plug my reference part into your code. but i have one compiling error:
 'findKeyValue' : cannot convert parameter 2 from 'const char *' to 'char *' Conversion loses qualifiers

please notice that i still use MyStrTok, just because i dont know how to use GetFields in my reference while loop (the first loop). So I copy my code here for your to correct them. Thanks

using namespace std;

const int MaxSize=1024;


int GetFields(std::string &aStr, std::vector<string> &aVec, char aDelim)
{
std::istringstream ss(aStr);
std::string field;
while (std::getline(ss, field, aDelim))
{
aVec.push_back(field);
}
return aVec.size();
};

string removechars( string &st, string delim )
{
    string result = "";

    size_t npos1 = 0, npos2 = 0;
    while ((npos2 = st.find_first_of(delim, npos1)) < st.length())
    {
        result += st.substr(npos1, (npos2-npos1));
        npos1 = npos2 + 1;
    }
    result += st.substr(npos1);
    return result;
};

void DateConvert(string &date)
{
    int day, month, year;
    if ( sscanf ( date.c_str(), "%d/%d/%d", &month, &day, &year ) == 3 )
    {
        char newdate[32];
        sprintf(newdate, "%02d%02d%04d", month, day, year );
        date = newdate;
    }
};

//////////////////////////////////
// struct for reference data
//////////////////////////////////
typedef struct
{             char keyData[100];
            char valueData[100];
}KeyRef;


//////////////////////////////////////////
// function to lookup value by key
//////////////////////////////////////////
char* findKeyValue(KeyRef* ref, char* k){
   
     for (int i=0;i<MaxSize;i++){
          if (!strcmp(ref[i].keyData,k))
               return ref[i].valueData;
     }
    return "None";
            
};

char* MyStrTok(char* text, const char del)
{
    static char *curTok = NULL;
    char *result = NULL;
    if ( text != NULL )
    {
        curTok = text;
    }
    result = curTok;
    if ( curTok != NULL )
    {
        //curTok = ::strchr(curTok, del);
        curTok = strchr(curTok, del);

        if ( curTok != NULL ) *curTok++ = 0;
    }
    return result;
};

main(int arc, char *arv[])
{
    ifstream fin("fin.txt");
    ofstream fout("fout.txt");
    string row_read;

    ifstream fin2("frefer.csv");
    ofstream fout2("refer_out.txt");
    KeyRef refer_data[MaxSize];
    char refer_read[MaxSize];
    char refer_row_elem[2][MaxSize];
    int j=0,k=0;
      int isFirstLine = 0;

            //////////////////////////////////////////
            // read refer file into struct of array
            //////////////////////////////////////////
while( fin2.getline( refer_read,MaxSize ))
{
    /////////////////////////////////////////////////
      // skip first line of reference file " frefer
      /////////////////////////////////////////////////
     if( isFirstLine == 0)
     {
            isFirstLine = 1;
     }
     else {

       char *tok = MyStrTok(refer_read,',');
           while( tok != NULL) {
          strcpy(refer_row_elem[j],tok);

          tok= MyStrTok(NULL,',');
          j++;
           }
           strcpy(refer_data[k].keyData, refer_row_elem[0]);
           strcpy(refer_data[k].valueData, refer_row_elem[1]);
           j=0;
           k++;
     }
      
}

///////////////////////////// below is drichard's code///////////////////////////
///////////////////////////////////////////////////////////////////
// for each line of file  
// assume there are 7 columns in each row in file fin.txt
///////////////////////////////////////////////////////////////////
//////////////////////////////////////////
// skip first line
//////////////////////////////////////////
    std::getline(fin, row_read);

    while( std::getline(fin, row_read) )
    {

        //////////////////////////////////////////
        // get tokens into row_elem, parse string with ","
        //////////////////////////////////////////
        vector<string> row_elem;
        GetFields(row_read, row_elem, ',');

        for ( unsigned ii = 0; ii < row_elem.size(); ii++ )
        {
            string &curStr = row_elem[ii];
            ///////////////////////////////////////////////////////////
            // remove '"', '=' in the fields
            //////////////////////////////////////////////////////////
            curStr = removechars(curStr, "\"=");

            ////////////////////////////////////
            // put space in empty columns
            ////////////////////////////////////
            if (curStr.empty()) {
                curStr = " ";
            }

            ////////////////////////////////
            // convert date field
            ////////////////////////////////
            if (ii == 6)             // Only 7 columns according to comment at start?????
            {
                DateConvert(curStr);
            }
                  

            } //end of for loop

    row_elem[2] += "-";
    row_elem[2] += row_elem[1];
    std::vector<string>::iterator iter = row_elem.begin();
    iter++; // move to second column
    //row_elem[1].erase(iter); // erase the 2nd column that was appended to column 3
    //cout<<row_elem[2].c_str()<<endl; // old column 2 was erased.

     //////////////////////////////////////////////////////////////////////
     // get reference value by looking at key in reference file
     //////////////////////////////////////////////////////////////////////
     char* valueFound;
     valueFound = findKeyValue(refer_data, row_elem[0].c_str());   /////// I add row_elem[0].c_str() here
                                                                                                /////// and compiling error here
            ////// 'findKeyValue' : cannot convert parameter 2 from 'const char *' to 'char *' Conversion loses qualifiers

     //cout << " value found - " << valueFound << endl;

cout                      << setw(2) << "01"
            << setw(10) << row_elem[1].c_str()
            << setw(10) << row_elem[2].c_str()
            << setw(10) << row_elem[3].c_str()
            << setw(10) << row_elem[4].c_str()
            << setw(10) << row_elem[5].c_str()
            << setw(10) << row_elem[6].c_str()
            << setw(10) << row_elem[7].c_str()
            << setw(1) << "s"
            << endl;
            ii==0;
    }//end of while
return 0;
}
0
 
drichardsCommented:
Here are tha changed parts:

1) changed second param of findKeyValue to const char* to get rid of compile error.
2) Changed first read loop to use GetFields.
----------------------------------------------------------------
//////////////////////////////////////////
// function to lookup value by key
//////////////////////////////////////////
char* findKeyValue(KeyRef* ref, const char* k){
   
     for (int i=0;i<MaxSize;i++){
          if (!strcmp(ref[i].keyData,k))
               return ref[i].valueData;
     }
    return "None";
         
};

main(int arc, char *arv[])
{
    ifstream fin("D:\\DevProjects\\CPPConsole\\fin.txt");
    ofstream fout("D:\\DevProjects\\CPPConsole\\fout.txt");
    string row_read;

    ifstream fin2("D:\\DevProjects\\CPPConsole\\frefer.txt");
    ofstream fout2("D:\\DevProjects\\CPPConsole\\refer_out.txt");
    KeyRef refer_data[MaxSize];
    string refer_read;
    int k=0;

    //////////////////////////////////////////
    // read refer file into struct of array
    //////////////////////////////////////////

    /////////////////////////////////////////////////
    // skip first line of reference file " frefer
    /////////////////////////////////////////////////
    std::getline(fin2, refer_read);
    while(std::getline(fin2, refer_read))
    {
        std::vector<string> refer_row_elem;
        GetFields(refer_read, refer_row_elem, ',');

        strcpy(refer_data[k].keyData, refer_row_elem[0].c_str());
        strcpy(refer_data[k].valueData, refer_row_elem[1].c_str());
        k++;
    }

///////////////////////////// below is drichard's code///////////////////////////
///////////////////////////////////////////////////////////////////
// for each line of file  
// assume there are 7 columns in each row in file fin.txt
///////////////////////////////////////////////////////////////////
//////////////////////////////////////////
// skip first line
//////////////////////////////////////////
    std::getline(fin, row_read);

    while( std::getline(fin, row_read) )
    {

        //////////////////////////////////////////
        // get tokens into row_elem, parse string with ","
        //////////////////////////////////////////
        vector<string> row_elem;
        GetFields(row_read, row_elem, ',');

        for ( unsigned ii = 0; ii < row_elem.size(); ii++ )
        {
            string &curStr = row_elem[ii];
            ///////////////////////////////////////////////////////////
            // remove '"', '=' in the fields
            //////////////////////////////////////////////////////////
            curStr = removechars(curStr, "\"=");

            ////////////////////////////////////
            // put space in empty columns
            ////////////////////////////////////
            if (curStr.empty()) {
                curStr = " ";
            }

            ////////////////////////////////
            // convert date field
            ////////////////////////////////
            if (ii == 6)             // Only 7 columns according to comment at start?????
            {
                DateConvert(curStr);
            }
               

          } //end of for loop

        row_elem[2] += "-";
        row_elem[2] += row_elem[1];
        std::vector<string>::iterator iter = row_elem.begin();
        iter++; // move to second column
        //row_elem[1].erase(iter); // erase the 2nd column that was appended to column 3
        //cout<<row_elem[2].c_str()<<endl; // old column 2 was erased.

     //////////////////////////////////////////////////////////////////////
     // get reference value by looking at key in reference file
     //////////////////////////////////////////////////////////////////////
     char* valueFound;
     valueFound = findKeyValue(refer_data, row_elem[0].c_str());   /////// I add row_elem[0].c_str() here
                                                                                                /////// and compiling error here
            ////// 'findKeyValue' : cannot convert parameter 2 from 'const char *' to 'char *' Conversion loses qualifiers

     //cout << " value found - " << valueFound << endl;

    cout  << setw(2) << "01"
          << setw(10) << row_elem[1].c_str()
          << setw(10) << row_elem[2].c_str()
          << setw(10) << row_elem[3].c_str()
          << setw(10) << row_elem[4].c_str()
          << setw(10) << row_elem[5].c_str()
          << setw(10) << row_elem[6].c_str()
          << setw(10) << row_elem[7].c_str()
          << setw(1) << "s"
          << endl;
    }//end of while
return 0;
}
0
 
drichardsCommented:
And lastly, here's one that gets rid of MaxSize and the other char arrays - modifies findKeyValue and the KeyRef struct.  I'll be out for a while, so if you can save up other questions for later this afternoon.
-------------------------------------------------------------------------------------------------
//////////////////////////////////
// struct for reference data
//////////////////////////////////
 struct KeyRef
{
    string keyData;
    string valueData;
};

//////////////////////////////////////////
// function to lookup value by key
//////////////////////////////////////////
string findKeyValue(vector<KeyRef> &ref, string &k){
   
     for (unsigned i=0;i<ref.size();i++){
          if (ref[i].keyData == k)
               return ref[i].valueData;
     }
    return "None";
         
};

main(int arc, char *arv[])
{
    ifstream fin("fin.txt");
    ofstream fout("fout.txt");
    string row_read;

    ifstream fin2("frefer.csv");
    ofstream fout2("refer_out.txt");
    std::vector<KeyRef> refer_data;
    refer_data.reserve(32); // Make some space to avoid lots of reallocation
    string refer_read;
    int k=0;

    //////////////////////////////////////////
    // read refer file into struct of array
    //////////////////////////////////////////

    /////////////////////////////////////////////////
    // skip first line of reference file " frefer
    /////////////////////////////////////////////////
    std::getline(fin2, refer_read);
    while(std::getline(fin2, refer_read))
    {
        std::vector<string> refer_row_elem;
        GetFields(refer_read, refer_row_elem, ',');

        refer_data.push_back(KeyRef());
        KeyRef &ref = refer_data[refer_data.size()-1];
        ref.keyData = refer_row_elem[0];
        ref.valueData = refer_row_elem[1];
        k++;
    }

///////////////////////////// below is drichard's code///////////////////////////
///////////////////////////////////////////////////////////////////
// for each line of file  
// assume there are 7 columns in each row in file fin.txt
///////////////////////////////////////////////////////////////////
//////////////////////////////////////////
// skip first line
//////////////////////////////////////////
    std::getline(fin, row_read);

    while( std::getline(fin, row_read) )
    {

        //////////////////////////////////////////
        // get tokens into row_elem, parse string with ","
        //////////////////////////////////////////
        vector<string> row_elem;
        GetFields(row_read, row_elem, ',');

        for ( unsigned ii = 0; ii < row_elem.size(); ii++ )
        {
            string &curStr = row_elem[ii];
            ///////////////////////////////////////////////////////////
            // remove '"', '=' in the fields
            //////////////////////////////////////////////////////////
            curStr = removechars(curStr, "\"=");

            ////////////////////////////////////
            // put space in empty columns
            ////////////////////////////////////
            if (curStr.empty()) {
                curStr = " ";
            }

            ////////////////////////////////
            // convert date field
            ////////////////////////////////
            if (ii == 6)             // Only 7 columns according to comment at start?????
            {
                DateConvert(curStr);
            }
               

          } //end of for loop

        row_elem[2] += "-";
        row_elem[2] += row_elem[1];
        std::vector<string>::iterator iter = row_elem.begin();
        iter++; // move to second column
        //row_elem[1].erase(iter); // erase the 2nd column that was appended to column 3
        //cout<<row_elem[2].c_str()<<endl; // old column 2 was erased.

     //////////////////////////////////////////////////////////////////////
     // get reference value by looking at key in reference file
     //////////////////////////////////////////////////////////////////////
    string valueFound = findKeyValue(refer_data, row_elem[0]);

    cout  << setw(2) << "01"
          << setw(10) << row_elem[1].c_str()
          << setw(10) << row_elem[2].c_str()
          << setw(10) << row_elem[3].c_str()
          << setw(10) << row_elem[4].c_str()
          << setw(10) << row_elem[5].c_str()
          << setw(10) << row_elem[6].c_str()
          << setw(10) << row_elem[7].c_str()
          << setw(1) << "s"
          << endl;
    }//end of while
return 0;
}
0
 
justinYAuthor Commented:
Thanks alot. your code is really neat
Now I am working on my last problem which is chopping row_elem[4] into 3 segments.
the first segment is cc,dd,ee,ff,gg,hh (from position1-2), the second segment is cc,dd,ee,ff,gg,hh (from position 3-4) and
the third segment is 5,5,5,5,5. so the output is
 
01       aaa    a3-aaa        a4                           100000  01012004         0    s
01       bbb    b3-bbb        b4                           200000  01152004         0    s
01       ccc    c3-ccc         c4     cc   cc        5    300000  01152004       977   s
01       ddd    d3-ddd        d4    dd   dd       5    400000  01152004     -9876  s
01       eee    e3-eee        e4    ee   ee       5    500000  01152004         0     s
01       fff      f3-fff           f4     ff     ff        5    600000  01152004     96543  s
01       ggg    g3-ggg        g4    gg   gg       5    700000  01152004    -99898  s
01       hhh    h3-hhh        h4    hh   hh       5    800000  01152004    -98656  s
01       iii       i3-iii            i4     ii      ii        5    900000  01152004         0     s

How can I do this ?
0
 
justinYAuthor Commented:
I have a function:
void substr(const char* src, int start, int len, char ** dest)
{
while ( *src && --start > 0)
src++;

while ( *src && len > 0)
{
**dest = *src;
*dest++;
src++;
len--;
}
**dest = 0x00;
}


so I do these:

substr ( row_elem[4].c_str(), 1, 2, row_elem[40].c_str());
substr ( row_elem[4].c_str(), 3, 2, row_elem[41].c_str());
substr ( row_elem[4].c_str(), 5, 1, row_elem[42].c_str());

I substr row_elem[4] 3 times, and write them to temperary location which are row_elem[40], [41] ,and [42]
then I write to file
but, I get compiling errors. Whats wrong ?
0
 
drichardsCommented:
You cannot use c_str() to get an editable character array.  You can take substrings like this:

if ( row_elem[4].length() > 4 )
{
   /* string part1 = */ row_elem[4].substr(0,2);
   /* string part2 = */ row_elem[4].substr(2,2);
   /* string part3 = */ row_elem[4].substr(4,1);
}

If you want to insert them into row_elem, you can do that using row_elem.insert, but you need to get an iterator to the insert position (similar to the erase that was in an earlier sample).  Otherwise, you can just get the parts as shown.
0
 
drichardsCommented:
If you want to add then to the end of row_elem, you need to use push_back:

    row_elem.push_back(row_elem[4].substr(0,2));
    row_elem.push_back(row_elem[4].substr(2,2));
    row_elem.push_back(row_elem[4].substr(4,2));

Now the new elements will be at positions 8, 9, and 10 since the original had 0 to 7.  You'd be better off just making a custom output function that did:

    cout  << ... << row_elem[4].substr(0,2).c_str() << ... << row_elem[4].substr(2,2).c_str() <<  ... etc.

unless you find it useful to store the temporaries for some reason.
0
 
justinYAuthor Commented:
when I do this:
                           cout<< setw(10) << part1
             << setw(10) << part2
             << setw(10) << part3
             << endl;
It displays what I want on the screen.

But when I do this:
                            fout<< setw(10) << part1
             << setw(10) << part2                         <<       I have compiling errors
             << setw(10) << part3
                                 <<endl;
or do this:
                           fout<< setw(10) << row_elem[4].substr(0,2)
            << setw(10) << row_elem[4].substr(2,2)                 <<            I have run time error
            << setw(10) << row_elem[4].substr(4,1)
                                << endl;
0
 
justinYAuthor Commented:
also, look my input file
="111",="aaa",a3,a4,,100000,01/01/2004,0
="222",="bbb",b3,b4,,200000,01/15/2004,0
="333",="ccc",c3,c4,cccc555,300000,01/15/2004,977
="444",="ddd",d3,d4,dddd555,400000,01/15/2004,-9876
="555",="eee",e3,e4,eeee555,500000,01/15/2004,0
="666",="fff",f3,f4,ffff555,600000,01/15/2004,96543
="777",="ggg",g3,g4,gggg555,700000,01/15/2004,-99898
="888",="hhh",h3,h4,hhhh555,800000,01/15/2004,-98656
="999",="iii",i3,i4,iiii555,900000,01/15/2004,0

in the first 2 rows of row_elem[4], they are empty, so it should be displayed like this:
            <<      reserve 2 empty spaces here
            <<
cc cc 5
dd dd 5
ee ee 5
ff ff 5
gg gg 5
hh hh 5
ii ii 5




0
 
justinYAuthor Commented:
It works. Thank you very very much for your help. Its my fortune meeting you here.
YOU ARE THE BEST.
0
 
justinYAuthor Commented:
How can I add more points ?
I think these question and answers deserve more than 125. Thanks
0
All Courses

From novice to tech pro — start learning today.