Thread: Searching for an entry in a file?

  1. #1
    Registered User
    Join Date
    Aug 2004
    Posts
    12

    Searching for an entry in a file?

    I have a problem regarding the code for searching a text file. My program is able to add information, display, and save it to a text file, but I'm having trouble figuring out how to search the text file for a particular entry.

    The entries in my text file look like this:

    0843543 Intro to C++ HH117

    I'm trying to implement a function to search the text file by the first value (ie: 0843543). I tried using a strcmp but it would not find the match.

    The code for this was:
    Code:
     void SearchClass()
    {
    	char input[7];
    	char course[7];
    	int i;
    	cout<<"enter in course to search: ";
    	cin>>course;
    
    	fstream readfile;
    	readfile.open("C:/WINDOWS/Desktop/class.txt", ios::in);
    	readfile.getline(input, 7);
    
    	while(!readfile.eof())
    	{
    		
    		
    		if(strcmp(course, input)==0)
    		{cout<<"match";}
    		else
    		{cout<<"no match";}
    		readfile.getline(input, 7);
    
    	}
    	readfile.close();
    
    }
    Once it finds the match I need to be able to delete it or change it. Thanks again for all the help.

  2. #2
    Sweet
    Join Date
    Aug 2002
    Location
    Tucson, Arizona
    Posts
    1,820
    you could just use the plain old >> like this to read the first line with no whitespace
    Code:
     void SearchClass()
    {
    	int input;
    	int course;
    	int i;
    	cout<<"enter in course to search: ";
    	cin>>course;
    
    	fstream readfile;
    	readfile.open("C:/WINDOWS/Desktop/class.txt", ios::in);	
    
    	while(!readfile.eof())
    	{
    		
    		readfile>>input;
    		if(course==input)
    		{cout<<"match";}
    		else
    		{cout<<"no match";}
    		
    
    	}
    	readfile.close();
    
    }
    Last edited by prog-bman; 08-08-2004 at 07:48 PM.
    Woop?

  3. #3
    Registered User
    Join Date
    Aug 2004
    Posts
    12
    The input and course has to be a char array because if int is used it does not work with my program and simply replies "no matchno matchno". Are there any other suggestions for searching through a text file that has char string elements? Thanks for the help.

  4. #4
    Registered User
    Join Date
    Aug 2001
    Posts
    247
    Your char arrays need to be 8 characters long (bytes) to store the information read from the file. In fact you would do better to read the file and store one line at a time, so you would need to have another array of char to hold that value. Have a look at the cstring function strncpy.

    Code:
    void SearchClass()
    {
    	char input[8];
    	char course[8];
            char lineread[50];
    	int i;
    	cout<<"enter in course to search: ";
    	cin>>course;
    
    	fstream readfile;
    	readfile.open("C:/WINDOWS/Desktop/class.txt", ios::in);
                    // reads line of text from file
    	readfile.getline(lineread, 50);
    
    	while(!readfile.eof())
    	{
    		// copies first 7 characters into input from line read
    		strncpy(input, lineread, 7);
                    // ensures null terminated
                    input[7] = '\0';
                    // "\n" puts each result on one line
    		if(strcmp(course, input)==0)
    		{cout<<"match\n";}
    		else
    		{cout<<"no match\n";}
    		readfile.getline(lineread, 50);
    
    	}
    	readfile.close();
    
    }
    I havenot tested this as have no compiler here at moment, but you should get the jest of whats happening. You should have test to ensure the file opens to read ok and also some way of ensuring the user inputs only the seven character course number.
    hoping to be certified (programming in c)
    here's the news - I'm officially certified.

  5. #5
    Registered User
    Join Date
    Sep 2001
    Posts
    4,912
    So then just do the same thing with a char array

    edit: never saw the reply above mine

  6. #6
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    A slightly more complex method would be to use a std::map and std::string.
    Code:
    typedef std::map<int, std::string> t_coursemap;
    t_coursemap courses;   //holds all the entries
    
    //variables for input
    int courseNum;
    char input[50];
    
    //Read in the whole file
    file >> courseNum;
    file.getline(input);
    
    while(!file.eof())
    {
       courses[courseNum] = input;
    
       file >> courseNum;
       file.getline(input);
    }
    
    //Search for and modify a course by course number
    std::cout << "Enter course number: ";
    std::cin >> courseNum;
    
    t_coursemap::iterator result = courses.find(courseNum);
    
    if(result != courses.end())
    {
       std::cout << "Match found. Course is: " << (*result).second.c_str() << std::endl;
       std::cout << "Enter new name: ";
       std::cin >> input;
       (*result).second = input;
    }
    else
    {
       std::cout << "No match." << std::endl;
    }
    
    //Write the modified file out
    std::ofstream newFile("modified.txt");
    for(t_coursemap::iterator it = courses.begin(); it != courses.end(); ++it)
    {
       newFile << (*it).first << " " << (*it).second.c_str() << std::endl;
    }
    Maps are fun I hope this helps. Also, I don't believe there's any easy way to delete or modify entries in a file; the only way I know of that's foolproof is to delete the file and re-write it with the modifications.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  7. #7
    Registered User
    Join Date
    Jan 2003
    Posts
    311
    Code:
    #include <iostream>
    #include <string>
    #include <fstream>
    #include <map>
    
    int main()
    {
        using std::cin; using std::cout; using std::endl;
        using std::string;
        typedef std::map<string, string> class_map_t;
        typedef class_map_t::iterator mit_t;
        class_map_t map;
        { 
            std::ifstream ifs("class.txt");
            for(string id,line;std::getline(ifs>>id, line);) map[id] = line;
            if(!ifs.eof()) {
                std::cerr << "Error processing file" << endl;
                return 1;
            }
        } // file safely closed here by desturctor  
        string cmd = "help";
        do {
            if(cmd == "list") {
                for(mit_t it=map.begin();it!=map.end();++it) 
                    cout << it->first << it->second << endl;
            } else if(cmd == "help"){
                cout << "Enter an id (7 numbers) to search for,\n"                        
                     << "'list' to list all entries,\n"
                     << "'help' for this message or,\n"
                     << "'quit' to quit" << endl;
            } else { // assume ID
                mit_t it=map.find(cmd);
                if(it!=map.end()) {
                    cout << it->first << it->second << endl;
                } else {
                    cout << cmd << " not found" << endl;
                }
            }
            cout << "\n :";
        } while(cin >> cmd && cmd != "quit");
        return 0;
    }
    Ok, I probably did too much work for you, not only that but now on preview Hunter2 has made many of the same points, but once you build a little bit you just keep on going. Anyway this is a slightly sloppy version of how I would do it using the stl. Namely, whenever you are going to want to serarch for something by a string use a map. When parsing files always check fail and badbits before using the result of the IO, never have eofbit control a loop. eof() is what tells you everything worked and your done, and that's why you left the loop.

    reading std::getline(ifs>>id,line) takes some getting used to, ifs>>id skips whitespace and copies the first whitespace terminated string into id, it returns ifs(an istream) getline takes an istream and puts everything up to newline into line. eats newline and returns ifs the for loop evalueates ifs in a boolean context and will therefore see true iff (!ifs.fail() && !ifs.bad()).

    map[id]=line assigns line to the record with key id, creating an empty (default constructed string in this case) record if none exists.

    one minor gotcha is that if your file had two lines starting with the same string then only the second will be in the map (the first gets overwritten) This could be a way to delete or modify records by simply appending new records with duplicate ID's to the file, this gives a faster and somewhat more reliable way of making changes to the file, as well as a way to undo all modifications and deletions. On the downside the file will grow ever larger and starting up will grow ever slower.

  8. #8
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Code:
        { 
            std::ifstream ifs("class.txt");
            for(string id,line;std::getline(ifs>>id, line);) map[id] = line;
            if(!ifs.eof()) {
                std::cerr << "Error processing file" << endl;
                return 1;
            }
        } // file safely closed here by desturctor
    Wow, I like that... unreadable, but compact and effective

    A lot of the .c_str() and char[] stuff that I used were because of bad experiences in the past with incompatibilities with std::string, and I couldn't remember exactly what was compatible and what wasn't (and didn't feel like testing ). If >> and << for the various (i/o)stream's work with std::string's, then yeah by all means don't bother with c_str() and char[].

    >>one minor gotcha is that if your file had two lines starting with the same string then only the second will be in the map

    Well, a course only has one name. Not sure why you'd want 2 entries with the same course number, but I guess there's always special cases...
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  9. #9
    Registered User
    Join Date
    Jan 2003
    Posts
    311
    Quote Originally Posted by Hunter2
    Well, a course only has one name. Not sure why you'd want 2 entries with the same course number, but I guess there's always special cases...
    Basically because it's easier to append a line to a text file than to copy a text file changeing only one line. It makes it confusing for people editing the file in notepad. The map looks just like you had edited the lines yourself, except it will have a number of odd records with null lines.

    Edit:
    Just about everything works with std::strings, except filenames for iostreams. There's also no good way to say capacity and resise but don't touch, so you can't make string a target for ifstream::read() without zeroing memory you are just going to blow away anyway. Really need a read eqivilent to function getline for strings.
    Last edited by grib; 08-08-2004 at 11:00 PM. Reason: one more thing,

  10. #10
    Registered User jlou's Avatar
    Join Date
    Jul 2003
    Posts
    1,090
    Hunter2, in MSVC++ 6.0, if you include <iostream> but forget to include <string>, you will be able to use the string class but not with the iostreams. It's strange, but I've had that happen to me and seen it happen to others, which is why some people use .c_str() to output strings. If both headers are included you shouldn't have any problems.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. gcc link external library
    By spank in forum C Programming
    Replies: 6
    Last Post: 08-08-2007, 03:44 PM
  2. Basic text file encoder
    By Abda92 in forum C Programming
    Replies: 15
    Last Post: 05-22-2007, 01:19 PM
  3. Game Pointer Trouble?
    By Drahcir in forum C Programming
    Replies: 8
    Last Post: 02-04-2006, 02:53 AM
  4. Possible circular definition with singleton objects
    By techrolla in forum C++ Programming
    Replies: 3
    Last Post: 12-26-2004, 10:46 AM
  5. Simple File encryption
    By caroundw5h in forum C Programming
    Replies: 2
    Last Post: 10-13-2004, 10:51 PM