?
Solved

Need Program help reading files and using the strtok function?

Posted on 2003-03-20
33
Medium Priority
?
352 Views
Last Modified: 2010-08-05
I have this program that I have to write. It has something like this "Cole","Georgey","","34","34242"
I want to get rid of all the commas and quotation marks and then rearrange the data in a chart type form.
ex.
first Name last name   number age
George      Cole       34242  34

note : I am reading several lines from a file when I tried the strtok command I kept getting NULL and it erased some of my data. I can't get the data rearranged or get rid of both the " and ,.  Is there another function I could use and what is it and how does it work?

Thank you
0
Comment
Question by:Rapieno
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 17
  • 10
  • 5
  • +1
33 Comments
 
LVL 6

Expert Comment

by:gj62
ID: 8176872
You want to use strtok - you just have to realize it corrupts the original string, so make a copy...
0
 
LVL 6

Expert Comment

by:gj62
ID: 8176921
e.g.

FILE *inFile, *outFile;
char inBuffer[100];outBuffer[100];
char delims[]=",";
char * lname, fname, num, age;

inFile = fopen("infile.txt","r");

while(!feof(inFile))
{
  fgets(inBuffer, sizeof(inBuffer), inFile);
  lname = strtok(inBuffer, delims);
  fname = strtok(NULL, delims);
  num = strtok(NULL, delims);
  age = strtok(NULL, delims);
  sprintf(outFile,"%20s%20s%10s%10s", fname, lname, num, age);
}
0
 
LVL 6

Expert Comment

by:gj62
ID: 8176946
hmmm, you still have the double-quotes to deal with...

Here's a function to replace them with spaces.  If you know you won't have embedded commas, just call it once right after fgets.  If not, call it for each token assigned, e.g.

lname = strtok(inBuffer, delims);
removeQuotes(lname);

(shouldn't goof formatting, and this way you don't corrupt the string for strtok...)

void removeQuotes(char * str)
{
  int i;
  for ( i = 0; i < strlen(str); ++i)
  {
    if (str[i]=='"') str[i]==' ';
  }
}

0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 6

Expert Comment

by:gj62
ID: 8176963
typo,

if(str[i]=='"')
  str[i]=' ';

had an extra =...
0
 

Expert Comment

by:mirko_germany
ID: 8177207
to get out the kommas and quotation marks, write that: e.g. you've got the string in a char-pointer called string:

char *string;
int i=0;

do
{
   if(string[i]=='\0') // last character of a string is \0
   {
      break; // if string has ended, leave do-while
   }
   if(string[i]=='\"') /* backslash needed, to tell the compiler not to interprete the " as ", but as a character of a string*/
   {
      // to want you want to do, if a " is found
   }
   if(string[i]==',') // if komma found...
   {
      // tell the compiler what to do with the komma
   }
   if((string[i]!='\"')&&(string[i]!=',')) /* you can be sure, that you have a 'real' character */
   {
      // write e.g. the character into another string
   }
   i++;
} while(1); /* unending do-while is here no problem because of break*/
0
 
LVL 3

Expert Comment

by:prady_21
ID: 8192267
I sort of had the same problem a week back and i had got the reply from this place itself without using strtok

    char *ptr, *index;
    char array[20][500];
    char line[1000];
    int num,len,i,length;
    int FNM_CASEFOLD = 1, FNM_EXTMATCH = 1;
    while(gets(line))   //// Read the lines from file
    {
      //// Remove the double quotes (") here
      ////
       ptr = line;
       num = 0;
       while(index = strchr(ptr,',')) {
          len = index - ptr;
          if ( len > 0 ) {
             strncpy(array[num],ptr,len+1);
             length=strlen(array[num]);
             array[num][length+1] = '\0';
             ptr = index+1;
             num++;
          }
          else {
             array[num][0]='\0';
             ptr = index+1;
             num++;
          }
       }
       num++;

       printf("\n%d\n",num);
       for(i=0; i<num; i++) {
          printf("%s\n",array[i]);
       }
    }
0
 

Author Comment

by:Rapieno
ID: 8197884
This is the code I got so far I cannot seem to get it to work any of the above perhaps you could show how to intergrate it into this code

#include <stdio.h>

int main()
{
FILE *inFile;
char line1[2], line2[58], line3[100];
char delims=",";
char * lname, fname, num, age;

inFile = fopen("names2.txt","r");

while(fgets(line1, sizeof(line1), inFile) != NULL)
{
 fgets(line2, sizeof(line2), inFile);
 fgets(line3, sizeof(line3), inFile);
 printf("%s\n",line3);

}

}
0
 

Author Comment

by:Rapieno
ID: 8197901
Not line3 has the information I want line2 and 1 are garbage.
0
 
LVL 6

Expert Comment

by:gj62
ID: 8198005
What does your file look like?  In your code, line1 only has room for 1 character - it does not read the line, it only reads 1 character from your file.  line2 starts at the 2nd character in your file and reads 57 characters, or until the end of the line is encountered.

What exactly are you trying to read from?

This line shouldn't even compile:

char delims=",";

you should have to say:

char delims[]=",";
or
char *delims=",";

Won't this work for you?  It is a combo of my previous posts:

-------------------------------------------

void removeQuotes(char * str)
{
 int i;
 for ( i = 0; i < strlen(str); ++i)
 {
   if (str[i]=='"') str[i]==' ';
 }
}

int main()
{
FILE *inFile, *outFile;
char inBuffer[100];outBuffer[100];
char delims[]=",";
char * lname, fname, num, age;

inFile = fopen("infile.txt","r");

while(!feof(inFile))
{
 fgets(inBuffer, sizeof(inBuffer), inFile);
 lname = strtok(inBuffer, delims);
 removeQuotes(lname);
 fname = strtok(NULL, delims);
 removeQuotes(fname);
 num = strtok(NULL, delims);
 removeQuotes(num);
 age = strtok(NULL, delims);
 removeQuotes(age);
 sprintf(outFile,"%20s%20s%10s%10s", fname, lname, num, age);
}
}
0
 
LVL 6

Expert Comment

by:gj62
ID: 8198031
Sorry, had a number of typos - this one should run as-is

--------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void removeQuotes(char * str)
{
int i;
for ( i = 0; i < strlen(str); ++i)
{
  if (str[i]=='"') str[i]=' ';
}
}

int main()
{
FILE *inFile;
char inBuffer[100];
char delims[]=",";
char * lname, *fname, *num, *age;

inFile = fopen("infile.txt","r");

while(!feof(inFile))
{
fgets(inBuffer, sizeof(inBuffer), inFile);
lname = strtok(inBuffer, delims);
removeQuotes(lname);
fname = strtok(NULL, delims);
removeQuotes(fname);
num = strtok(NULL, delims);
removeQuotes(num);
age = strtok(NULL, delims);
removeQuotes(age);
printf("%20s%20s%10s%10s", fname, lname, num, age);
}

return(0);
}
0
 

Expert Comment

by:mirko_germany
ID: 8198100
i wrote a similar program a few days ago. i've got a file in witch a lot of numbers and characters are included which could look this way: 400|0|0|0|0|0|0|0|0|32|6|6|6|6|6|6|6|6|6|6|6|6|6|6|6|6|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|

then i want to get the variables of the file into character(string)s and integer(array)s. i solved this problem that way:
   handle2=open("F09.uni", O_RDONLY | O_BINARY, S_IWRITE | S_IREAD);
   if(handle2>0)
   {
        cout << "Auf F9 gespeicherte Abfolge wird geladen...\n";
      i=0;
        do
      {
           bytes = read(handle2, byte, 1);
             if(bytes<0)
         {
              cout << "Informationen in F09.uni sind ung"<<ue<<"ltig!\n";
            erfolg=0;
         }
         stream[i]=byte[0];
         i++;
      } while(bytes==1);
      aufg[0]=1;
      if (erfolg==1) (cout << "Abfolge erfolgreich geladen!\n");
      stream[i]='\0';
      filelen=i;
      intervall[0]=0;
      for(i=0;i<filelen;i++)
      {
           if(stream[i]=='|')
         {
              break;
         }
         if((stream[i]>=48) && (stream[i]<=57))
         {
                    intervall[0]=intervall[0]*10+stream[i]-48;
         }
      }
      for(j=0;j<8;j++)
      {
           anfang[0][j]=stream[i+1+j*2]-48;
      }
      max_i=i+19;
      max[0]=0;
      for(i+=17;i<max_i;i++)
      {
               max[0]=max[0]*10+stream[i]-48;
      }
          i++;
          for(j=0;j<max[0];j++)
      {
               schaltung[0][j]=stream[i+j*2]-48;
      }
      close(handle2);
   }

this is only a part of the whole programm, so that there are no declarations of variables and includings of headerfiles, but i hope you can do it yourself, can't you? is that what you wanted? write back

mirko
0
 
LVL 6

Expert Comment

by:gj62
ID: 8198146
ahem, Mirko -

That's an odd mixture of C++ & C.  What compiler are you using?  I really don't think this is going to help much for the current problem.

0
 

Expert Comment

by:mirko_germany
ID: 8198385
"What compiler are you using?":
i use borland c++ 5.01 for windows, even if i don't know, what my compiler-version could help to solve the problem.

"I really don't think this is going to help much for the current problem":
perhaps i didn't understand the problem right!? perhaps, because of my bad english!? however: isn't the problem, that rapieno wants to read the whole file and then wants to split it into different variables? that's exactly what this program does.

"That's an odd mixture of C++ & C":
replace the cout-commands with printf. then it's only c, isn't it? and you CAN mix it, and i think you HAVE TO mix it, because sometimes you need to use a function, and other times you need classes, don't you? look at your program: i think it should be c++, shouldn't it? but why do you use printf in the last line but three? and it's also a historical reason:

when i started program about five years ago i at first used basic. lateron i started programming with c. i learned a lot of functions in c and i learned how to write long programs about 50 pages. nearly one year ago, i started with oop. but why should i learn c++ as it's own language, instead of combining it with c? why let the compiler combine it, if it wouldn't be senseful? tell me!

mirko
0
 

Expert Comment

by:mirko_germany
ID: 8198415
and by the way @gj62:

if you want such a differenciating between c and c++, why do you write c++-code to the c-forum?
0
 
LVL 6

Expert Comment

by:gj62
ID: 8198476
Regarding my question about the compiler....   your code is not standard C.  I asked about your compiler to understand where you were getting open() and read() from - these are not standard C calls, and they weren't used in their C++ form either.  So unless they have the Borland compiler, they are stuck.

Now, I know that Borland (and MSFT to some extent) historically have "extended" the language - but again, unless you *know* that someone has the Borland compiler, or will accept a non-standard answer, you should try to stick with ANSI C.  

About C++ comment....  You're right, there is generally no reason to not combine C & C++, *as long as you have C++ and can use it*.  C++ is a superset - it includes all of C, *plus* C++.  However, since this is the C forum, you should have your answers stick to C.  If people are using C++, it will generally be in the C++ forum.  

Please, no flames, this is only a guide, and I think a fair one that is followed more often than not.

About your code not really fitting the question....  Your code was very specific to reading numbers with only one type of delimiter and doing some manipulation on a char by char basis - I didn't find it all that enlightening on reading & writing strings.  

I certainly would not generally encourge anyone to read a file byte-by-byte like you are doing, and figured you probably had a specific reason to do so that wasn't clear from your code fragment.
0
 
LVL 6

Expert Comment

by:gj62
ID: 8198502
Mirko, you said:

"and by the way @gj62:

if you want such a differenciating between c and c++, why do you write c++-code to the c-forum? "

If I posted C++ to the C forum, it was inadvertent, or a modification of existing code that was already posted in the question.

What part of my code in this post is C++?  I even try to stick to C-style comments...  printf is a standard C function...
0
 

Expert Comment

by:mirko_germany
ID: 8198907
open/read/close-command: i don't know other ones (i've heared about fopen etc. but don't know how to use them. but if they have problems with the functions i'll send them the headers fcntl.h and io.h.

code not fitting question: if they are not able to replace char by int, i'm sorry!

byte-by-byte-reading: i read the file byte by byte not to get conflicts with the eof. using the open-command i tell the compiler how many bytes i want to read. when i tell him: read 5gb he'll get an eof-error, and i have none of those bytes. so i read only one byte and save it to the array. if then the eof comes i get a -1 and know: eof, but the read bytes are already in the array and i can work with them. i'm sure, that there are better possibilities, but this works. and i never know if other methodes also work that good.

different question: can i set the attributes of a file (hidden, system, archive, write protect) by using fwrite? would be helpful, because using write it sometimes sets a write protect attribute and sometimes not, but it mustn't set it, because else i need to write other expressions to the file later.

c++ in c-forum: sorry, i didn't knew the command strtok and so i called it oop - sorry! but my code also is c (except cout). ok, if you called open, read, close, c++: no problem.
0
 
LVL 6

Expert Comment

by:gj62
ID: 8199043
Use fopen() - it works similarly and is portable.  That said, if you use such a command and attempt to read past the end-of-file, you still get the information in your buffer.  I suggest you work with them to understand how to get what you need.  While you can't read 5GB, you can read up to an unsigned int's worth of data in one pass, but I don't know why you'd want to.  When working with binary files, or text files with no EOL delimiters, I'd suggest reading in blocks of 64K at a time (or multiples thereof) to speed disk access.  

However, Rapieno appears to be working with text files (each line having discrete information).  It is MUCH easier for them to use fgets, which will read an entire line at a time.

Neither write nor fwrite sets the attribute.  This is OS and compiler specific.
0
 

Author Comment

by:Rapieno
ID: 8211935
I guess this is giving you guys some troubles here is the code that I should have put down instead.

#include <stdio.h>

int main()
{
FILE *inFile;
char line1[2], line2[58], line3[100];
char * lname, fname, num, age;

inFile = fopen("names2.txt","r");

while(fgets(line1, sizeof(line1), inFile) != NULL)
{
fgets(line2, sizeof(line2), inFile);
fgets(line3, sizeof(line3), inFile);
printf("%s\n",line3);

}

}

I will put down and example in detail of array line[3] in the code you can see that line2 and line1 are totally disregarded hopefully by this you can give me some useful advice.
"firstname","lastname","","word","email@email.com"
that is the data in line3 is that I want to extract.
and manipulate to look like this.
Ex.
Last Name   First Name   Email
lname       fname        email@site.com

I hope this is enough information assist me in solving my problem.:-)
0
 

Author Comment

by:Rapieno
ID: 8211950
Ignore the line
char * lname, fname, num, age;
I was trying something and forgot to delete it!
Sorry
0
 
LVL 6

Expert Comment

by:gj62
ID: 8212117
There have been a number of suggestions given - have you tried any of them?  Can you post the first 10 lines of your text file EXACTLY as they exist?
0
 
LVL 6

Expert Comment

by:gj62
ID: 8212184
This will give you what you are looking for, based on your explanations...

-----------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void removeQuotes(char * str)
{
int i;
for ( i = 0; i < strlen(str); ++i)
{
 if (str[i]=='"') str[i]=' ';
}
}

int main()
{
FILE *inFile;
char inBuffer[100];
char delims[]=",";
char * lname, *fname, *num, *email;

inFile = fopen("infile.txt","r");

/* skip 2 lines... */
fgets(inBuffer, sizeof(inBuffer), inFile);
fgets(inBuffer, sizeof(inBuffer), inFile);

while(!feof(inFile))
{
fgets(inBuffer, sizeof(inBuffer), inFile);
lname = strtok(inBuffer, delims);
removeQuotes(lname);
fname = strtok(NULL, delims);
removeQuotes(fname);
num = strtok(NULL, delims);
removeQuotes(num);
email = strtok(NULL, delims);
removeQuotes(age);
printf("%20s%20s%30s", fname, lname, age);
}

return(0);
}
0
 
LVL 6

Accepted Solution

by:
gj62 earned 300 total points
ID: 8212190
Sorry, typo, use this one...

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void removeQuotes(char * str)
{
int i;
for ( i = 0; i < strlen(str); ++i)
{
if (str[i]=='"') str[i]=' ';
}
}

int main()
{
FILE *inFile;
char inBuffer[100];
char delims[]=",";
char * lname, *fname, *num, *email;

inFile = fopen("infile.txt","r");

/* skip 2 lines... */
fgets(inBuffer, sizeof(inBuffer), inFile);
fgets(inBuffer, sizeof(inBuffer), inFile);

while(!feof(inFile))
{
fgets(inBuffer, sizeof(inBuffer), inFile);
lname = strtok(inBuffer, delims);
removeQuotes(lname);
fname = strtok(NULL, delims);
removeQuotes(fname);
num = strtok(NULL, delims);
removeQuotes(num);
email = strtok(NULL, delims);
removeQuotes(email);
printf("%20s%20s%30s", fname, lname, email);
}

return(0);
}
0
 

Author Comment

by:Rapieno
ID: 8212291
I am afraid that my text is confidential information and cannot be given to you. Here is something close that is random.
Note space first line!
file starts here:

"11","Z","8928","9","XXXX","XX","898B","003","123456789","firstname","lastname","","word","email@email.com"

"11","Z","8928","9","XXXX","XX","898B","003","123456788","firstname","lastname","","word","email@email.com"

"11","Z","8928","9","XXXX","XX","898B","003","123456787","firstname","lastname","","word","email@email.com"

"11","Z","8928","9","XXXX","XX","898B","003","123456786","firstname","lastname","","word","email@email.com"

"11","Z","8928","9","XXXX","XX","898B","003","123456785","firstname","lastname","","word","email@email.com"

"11","Z","8928","9","XXXX","XX","898B","003","123456784","firstname","lastname","","word","email@email.com"

"11","Z","8928","9","XXXX","XX","898B","003","123456783","firstname","lastname","","word","email@email.com"

"11","Z","8928","9","XXXX","XX","898B","003","123456782","firstname","lastname","","word","email@email.com"

"11","Z","8928","9","XXXX","XX","898B","003","123456781","firstname","lastname","","word","email@email.com"

Hope this is enough
0
 

Author Comment

by:Rapieno
ID: 8212304
Yes I have they don't work for this program.
0
 

Author Comment

by:Rapieno
ID: 8212318
Yes I have they don't work for this program.
0
 
LVL 6

Expert Comment

by:gj62
ID: 8212495
This data is all on one line...  Is there a key you can look for on the line?

Let me see if I can summarize...

Each line contains 14 tokens.  Each token is surrounded by double quotes and separated by commas.  There may be blank lines...

You want the 10th, 11th,  and 14th tokens extracted and printed.

Does this describe the problem?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void removeQuotes(char * str)
{
int i;
for ( i = 0; i < strlen(str); ++i)
{
if (str[i]=='"') str[i]=' ';
}
}

int main()
{
FILE *inFile;
char inBuffer[100];
char delims[]=",";
char * lname, *fname, *num, *email, *pString;

inFile = fopen("infile.txt","r");

/* skip 2 lines... */
fgets(inBuffer, sizeof(inBuffer), inFile);
fgets(inBuffer, sizeof(inBuffer), inFile);

/* remove blanks line */
fgets(inBuffer, sizeof(inBuffer), inFile);
while(!feof(inFile))
{
fgets(inBuffer, sizeof(inBuffer), inFile);

/* get first 9 tokens and throw them away */
pString = strtok(inBuffer, delims);
for (i = 0; i < 8; ++i)
  pString = strtok(NULL, delims);

lname = strtok(inBuffer, delims);
removeQuotes(lname);
fname = strtok(NULL, delims);
removeQuotes(fname);

/* throw away 2 more tokens */
pString = strtok(inBuffer, delims);
pString = strtok(inBuffer, delims);


email = strtok(NULL, delims);
removeQuotes(email);
printf("%20s%20s%30s", fname, lname, email);

//skip another blank line...
fgets(inBuffer, sizeof(inBuffer), inFile);
}

Now, you can test for blank lines better, in case there could be more than 1, but this should work for you, IF your file is as you've described...


0
 

Author Comment

by:Rapieno
ID: 8212694
Well actually I manipulated your previous code and acutally got it to work. Thanks for the help it was greatly appreciated I will give you the points for the answer thanks gj62. Your a good help and programmer sorry for the descripency I just needed to switch a few things around as you will see.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void removeQuotes(char * str)
{
int i;
for ( i = 0; i < strlen(str); ++i)
{
if (str[i]=='"') str[i]=' ';
}
}

int main()
{
FILE *inFile;
char line1[3], line2[58], line3[100];
char delims[]=",";
char * lname, *fname, *num, *nothing, *email;
int count = 1;
printf("%2s%24s%19s%20s\n\n", "#", "Last Name", "First Name", "Email");
inFile = fopen("names.txt","r");

while(fgets(line1, sizeof(line1), inFile) != NULL)
{
fgets(line2, sizeof(line2), inFile);
fgets(line3, sizeof(line3), inFile);

lname = strtok(line3, delims);
removeQuotes(lname);
fname = strtok(NULL, delims);
removeQuotes(fname);
num = strtok(NULL, delims);
removeQuotes(num);
nothing = strtok(NULL, delims);
removeQuotes(nothing);
email = strtok(NULL, delims);
removeQuotes(email);
printf("%2i%25s%20s%20s",count ,fname, lname, email);
  count = count + 1;
}
printf ("\n");
system("PAUSE");
return(0);
}


Just one question is it possible to allign the program to the left and not the right side?
0
 
LVL 6

Expert Comment

by:gj62
ID: 8212967
Yes, add a minus sign to the printf specifier, as shown below - that will left-align each string within the width given:

printf("%-2i%-25s%-20s%-20s",count ,fname, lname, email);
0
 

Author Comment

by:Rapieno
ID: 8212971
Awsome man your great. My prog works perfect now thanks a lot.
0
 
LVL 6

Expert Comment

by:gj62
ID: 8212972
You'll want to do it for your header string too:

printf("%-2s%-24s%-19s%-20s\n\n", "#", "Last Name", "First Name", "Email");
0
 

Author Comment

by:Rapieno
ID: 8212986
Great Programmer he is really helpful and a good person to work with provides great help.
Thanks A Lot
0
 
LVL 6

Expert Comment

by:gj62
ID: 8213022
Glad I could help...
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
Examines three attack vectors, specifically, the different types of malware used in malicious attacks, web application attacks, and finally, network based attacks.  Concludes by examining the means of securing and protecting critical systems and inf…
The goal of this video is to provide viewers with basic examples to understand and use conditional statements in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use switch statements in the C programming language.
Suggested Courses

765 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question