Sh0gun
Sh0gun

Reputation: 931

Rewriting grep in C++

So I'm trying to write a progam that performs the same task as grep. In the end I want a program that takes four arguments, the second being what to search for, the third being the input file and the fourth being the output file. I think I've got a good grasp on how to go about it, but as usual the theory come easy and the actual programming I get all confused. Basically where I'm at now I've got the file in and I'm trying to search it and get the all of the lines that contain what I'm searching for, as well as the line of that number.

I want to use a vector to achieve this task. I am not entirely sure how to go about it. Would it be easier to go through and add each line to the vector individually and then go through and pick out those that have the desired string in them and use thier array location as the line number? I would like to think there is a way of only adding those lines to the vector which contain the desired string, but then I'm not sure how to get the line number. I've started a couple times and then erased what I ahd when I realized it was all wrong.

This is where I'm at now:

#include <iostream>
#include <regex>
#include <string>
#include <fstream>
#include <vector>

using namespace std;

int main (int argc, char* argv[]){

// validate the command line info
if( argc < 2 ) {
    cout << "Error: Incorrect number of command line arguments\n"
            "Usage: grep\n";
    return EXIT_FAILURE;
}

//Declare the arguments of the array
string query = argv[1]; 
string inputFileName = argv[2];
string outputFileName = argv [3];

// Validate that the file is there and open it
ifstream infile( inputFileName );
if( !infile ) {
    cout << "Error: failed to open <" << inputFileName << ">\n"
            "Check filename, path, or it doesn't exist.\n";
    return EXIT_FAILURE;
}

else{
vector<string> queries;


}

}

}

Upvotes: 1

Views: 2050

Answers (2)

Jerry Coffin
Jerry Coffin

Reputation: 490108

Most of the complexity with implementing a complete grep would be handling the dozens of flags to modify how it works. A simplified version that doesn't try to support those and just searches a set of files for a specified pattern can be pretty simple. A C++11 version looks roughly like this:

#include <iostream>
#include <fstream>
#include <algorithm>
#include <string>
#include <regex>

class line {
    std::string data;
public:
    operator std::string() const { return data; }

    friend std::istream &operator>>(std::istream &is, line &l) {
        return std::getline(is, l.data);
    }
};

void process(std::regex const &pattern, std::istream &file) {
    typedef std::istream_iterator<line> in;
    typedef std::ostream_iterator<std::string> out;

    std::copy_if(in(file), 
                in(), 
                out(std::cout, "\n"), 
                [&](std::string const &s) {return std::regex_search(s, pattern);});
}

int main(int argc, char **argv) { 
    if (argc < 2) {
        std::cerr << "Usage: grep <pattern> [file specification]";
        return 1;
    }

    std::regex pattern(argv[1], std::regex::nosubs | std::regex::optimize);

    if (argc < 3)
        process(pattern, std::cin);
    else
        for (int i=2; i<argc; ++i) {
            std::ifstream infile(argv[i]);
            std::cout << "\t-- " << argv[i] << " --\n";
            process(pattern, infile);
        }
    return 0;
}

On Unix-like systems, you don't have to do anything special to build this. On Windows, you'll want to link with the compiler-supplied object file that handles globbing (e.g., setargv.obj, with MS VC++).

Upvotes: 1

bames53
bames53

Reputation: 88155

There's no need to use a vector. It seems to me you should just go through the input file a line at a time using std::getline, try to match each one against the regex, and output the lines that succeed immediately.

Upvotes: 2

Related Questions