Getting filename from command line argument?

Hello, I have written this code (apologies if it's a little hard to understand) and it works just fine, however I'm having trouble with a couple of things. First of all, I need to make functions readFileToSet and readFileToVector take a command line argument for the name of the file they should be reading. If I'm reading in [filename].txt, the input should be “filename” and I'm not sure how to go about that. Also the name of the output file for "write_set" should be “[filename]_set.txt”, where [filename] is the command - line input supplied by the user. I feel like I understand the general idea but I don't know how to correctly implement it.

Secondly, I'd like to get this to run properly on Linux, are there any adjustments I need to make for this to work correctly on a Linux platform?

If I've written this in a confusing way, feel free to ask me to clarify. Thank you for your time!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#include <string>
#include <fstream>
#include <iostream>
#include <vector>
#include <stdio.h>
#include <ctype.h>
#include <iterator>
#include <map>
#include <list>
#include <cctype>
#include <algorithm>
#include <set>
#include <sstream>
#include <time.h>

using namespace std;

void readFileToSet(string filename, set<string> &mySet)
{
	ifstream loadFile;

	loadFile.open(filename, ifstream::in);
	while (loadFile.fail()){
		cout << "The file \"" << filename << "\" failed to open.\n\n";
		exit(EXIT_FAILURE);
	}

	string line;
	while (getline(loadFile, line)){
		for (int i = 0, len = line.size(); i < len; i++)
		{
			if (ispunct(line[i]))
			{
				line.erase(i--, 1);
				len = line.size();
			}
		}
		istringstream iss(line);
		string word;
		while (iss >> word){
			mySet.insert(word);
		}
	}

	loadFile.close();
}


void write_set(set<string> &output) {
	cout << "\nEnter file name to save: ";
	string file_name_save;
	std::cin >> file_name_save;

	ofstream outfile(file_name_save);
	if (outfile.is_open()) {
		for (set<string>::iterator iter = output.begin(); iter != output.end(); ++iter){
		outfile << *iter << ' ';
		outfile << '\n';
		}
		outfile.close();
	}
	else{
		cout << "Unable to open file\n";
	}

}


void readFileToVector(string filename, vector<string> &myVec)
{
	ifstream loadFile;
	loadFile.open(filename, ifstream::in);
	while (loadFile.fail()){
		cout << "The file \"" << filename << "\" failed to open.\n\n";
		exit(EXIT_FAILURE);
	}


	string line;
	while (getline(loadFile, line)){
		for (int i = 0, len = line.size(); i < len; i++)
		{
			if (ispunct(line[i]))
			{
				line.erase(i--, 1);
				len = line.size();
			}
		}
		istringstream iss(line);
		string word;
		while (iss >> word){
			myVec.push_back(word);
		}
	}
	loadFile.close();
}


void write_file(vector<string> &output) {
	cout << "\nEnter file name to save: ";
	string file_name_save;
	cin >> file_name_save;

	ofstream outfile(file_name_save);
	if (outfile.is_open()) {
		for (int i = 0; i < output.size(); i++) {
			outfile << output[i] << "\n";
		}
		outfile.close();
	}
	else {
		cout << "Unable to open file\n";
	}
}

void write_file_comma(vector<string> &output) {
	cout << "\nEnter file name to save: ";
	string file_name_save;
	cin >> file_name_save;

	ofstream outfile(file_name_save);
	if (outfile.is_open()) {
		for (int i = 0; i < output.size(); i++) {
			outfile << output[i];
			outfile << ", ";
		}
		outfile.close();
	}
	else {
		cout << "Unable to open file\n";
	}
}

int main(/*int argc, char **argv???*/){ 
	vector<string> myVec;
	set<string> mySet;
	string charactersFilename/*(argv[1])???*/;
	cin >> charactersFilename;

	readFileToSet(charactersFilename, mySet);
	write_set(mySet);

	readFileToVector(charactersFilename, myVec);
	write_file(myVec);

	map<string, string> wordmaps;
	string last = "";
	for (vector<string>::iterator it = myVec.begin(); it != myVec.end(); it++){
		wordmaps[last] = *it;
		last = *it;
	}

	write_file_comma(myVec);

	cout << "\n\nPart 4\n\n" << endl;

	string state = "";
	for (int i = 0; i < 100; i++) {
		cout << wordmaps[state] << " ";
		state = wordmaps[state];
	}
	cout << endl;

	cout << "\n\nPart 5\n\n" << endl;

	map< string, vector<string> > wordmap;
	for (vector<string>::iterator it = myVec.begin(); it != myVec.end(); it++){
		wordmap[state].push_back(*it);
		state = *it;
	}
	
	srand(time(NULL));

	for (int i = 0; i < 100; i++){
			int ind = rand() % wordmap[state].size();
			cout << wordmap[state][ind] << " ";
			state = wordmap[state][ind];
	}
	cout << endl;

	cout << "\n\nPart 6\n\n" << endl;

	map<list<string>, vector<string>> wordmapies;
	list<string> states;
	for (int i = 0; i < 2; i++){
		states.push_back("");
	}
	for (vector<string>::iterator it = myVec.begin(); it != myVec.end(); it++){
		wordmapies[states].push_back(*it);
		states.push_back(*it);
		states.pop_front();
	}

	list<string> statos;
	for (int i = 0; i < 2; i++){
		statos.push_back("");
	}
	for (int i = 0; i < 100; i++){
		int ind = rand() % wordmapies[statos].size();
		cout << wordmapies[statos][ind] << " ";
		statos.push_back(wordmapies[statos][ind]);
		statos.pop_front();
	}
	cout << endl;

	system("PAUSE");
	return 0;
}
Last edited on
Something along these lines, perhaps:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <iostream>
#include <string>
#include <fstream>
#include <cctype>
#include <set>
#include <vector>
#include <sstream>

namespace
{
    const std::string ext = ".txt" ;

    std::string input_file_name( std::string base_file_name )
    { return base_file_name + ext ; }

    std::string output_file_name( std::string base_file_name )
    { return base_file_name + "_set" + ext ; }
}

bool parse_cmd_line( int argc, char* argv[] )
{
    if( argc != 2 )
    {
        std::cerr << "invalid command line\nusage: " << argv[0] << " <base name of file>\n" ;
        return false ;
    }

    const std::string in_file = input_file_name( argv[1] ) ;
    if( !std::ifstream(in_file).is_open() )
    {
        std::cerr << "unable to open input file '" << in_file << "'\n" ;
        return false ;
    }

    return true ;
}

std::string remove_punct( const std::string& str ) // can be reused over and over again
{
    std::string result ;
    for( char c : str ) if( !std::ispunct(c) ) result += c ;
    return result ;
}

std::vector<std::string> split( const std::string& line ) // can be reused over and over again
{
    std::vector<std::string> result ;

    std::istringstream stm( remove_punct(line) ) ;
    std::string tok ;
    while( stm >> tok ) result.push_back(tok) ;

    return result ;
}

std::set<std::string> read_into_set( const std::string& file_name )
{
    std::set<std::string> result ;
    std::ifstream file(file_name) ;

    std::string line ;
    while( std::getline( file, line ) )
    {
        const auto tokens = split(line) ;
        result.insert( tokens.begin(), tokens.end() ) ;
    }

    return result ;
}

template < typename CNTR >
bool write_from_cntr( const CNTR& cntr, const std::string& file_name )
{
    std::ofstream file( file_name, std::ios::app ) ;
    for( const auto& v : cntr ) file << v << '\n' ;
    return file.good() ;
}

bool write_from_set( const std::set<std::string>& set, const std::string& file_name )
{ return write_from_cntr( set, file_name ) ; }

int main( int argc, char* argv[] )
{
    if( parse_cmd_line( argc, argv ) )
    {
        const auto set = read_into_set( input_file_name( argv[1] ) ) ;
        write_from_set( set, output_file_name( argv[1] ) ) ;

        // etc
    }

    else return 1 ;
}


Note: std::ofstream outfile(file_name_save);
Each time the output file is opened this way, it would be truncated;
we would lose what was written earlier into the file.

Consider opening the file in append mode:
std::ofstream outfile( file_name_save, std::ios::app );
@JLBorges Wow, that was incredibly fast, thank you! Unfortunately I must embarrassingly admit I'm very much a beginner and your code confuses me a bit. Can you perhaps expand a little more on what you did? Ideally, I would like to maintain my previous code structure a bit more when making these changes just so I could more easily understand what's happening, is that at all possible? Again, thank you.
Last edited on
closed account (48T7M4Gy)
Here's a way to use the command line parameter(s) to get the file name. You need the relevant directory and suffix stuff but that could be an embellishment you might add to avoid that.
(Needless to say, forget the internal processing that goes on here.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Open a file from command line & display contents

// "open filename"

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

int main (int argc, char* argv[]) {
    std::string line;
    std::ifstream myfile ( *argv );
    
    if (myfile.is_open())
    {
        while ( getline (myfile, line) )
        {
            std::cout << line << '\n';
        }
        myfile.close();
    }
    
    else
        std::cout << "Unable to open file";
    
    return 0;
}
> Can you perhaps expand a little more on what you did? Ideally, I would like to maintain my
> previous code structure a bit more when making these changes just so I could more easily
> understand what's happening, is that at all possible?

Start with this small step (just parsing the command line and extracting the file name):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <string>

int main( int argc, char* argv[] )
{
    // argc - the number of command line arguments passed to the program
    //        this would be a positive value: the first argument argv[0]
    //        is always passed; this is an implementation defined string
    //        that contains the name used to invoke the program.
    // argv[] is an array of null terminated strings; argv[1] to argv[argc-1]
    //        contain the command line arguments after the name of the program
    //
    // for example, if the program was invoked with the command line: ./my_xyz_program my_file
    // argc would be 2, argv[0] would contain the equivalent of "./my_xyz_program",  
    // and argv[1] would contain "my_file"
    //
    // more information: http://en.cppreference.com/w/cpp/language/main_function
    if( argc != 2 ) // if the program was invoked with the wrong number of command line arguments
    {
        // print out an error message indicating correct usage and return a failure code
        // note that we use argv[0] (the name of the program) as part of the the message
        // this is guaranteed to be present; argc is atleast one
        std::cerr << "invalid command line\nusage: " << argv[0] << " <base name of file>\n" ;
        return false ;
    }

    // if we got here, the program was invoked with exactly one argument after the name used
    // to invoke the program; this argument would be placed in argv[1]
    const std::string base_name_of_file = argv[1] ;
    const std::string input_file_name = base_name_of_file + ".txt" ; // add .txt to it to get the input file name
    const std::string output_file_name = base_name_of_file + "_set.txt" ; // add _set.txt to it to get the output file name

    // perform a sanity check by printing out the values:
    std::cout << "command line argument: '" << argv[1] << "'\n"
              << "input file name: '" << input_file_name << "'\n"
              << "output file name: '" << output_file_name << "'\n";

    // rest of main
}
Last edited on
@kermot @JLBorges Thank you so much for your incredible help! After studying your code and messing with it a bit more, I finally made it work the way I was hoping for and in a way I can understand. Thanks again for your time and patience, I couldn't have asked for better help, your input was extremely valuable!
Topic archived. No new replies allowed.