How to print related lines in c++? - c++

In my code, I want to have a function called search that goes through each line in a .txt file and prints out the line if the first number in the sentence contains the number given by the user. For example:
Format of the .txt file:
Each word is separated by a space.
17 35 "door"
40 19 "wall"
17 34 "car"
3 9 "window"
Output:
Enter a desired number:17
17 35 "door"
17 34 "car"
How would I go about doing this? In java, I would normally use the .split() function to split the sentence into a list then see if the first index matches the desired input, but I can't find how to do this, and what I can find, I don't understand. My attempts are listed below, but if you have better methods, please list them...I'm still learning. My attempt are located under the search function below:
#include<iostream>
using std::cerr;
using std::endl;
#include <list>
using namespace std;
#include <fstream>
using std::ofstream;
#include <cstdlib> // for exit function
#include <sstream>
using namespace std;
class Item{
//Access specifer
public: //todo, private with get/set
string item;
int meshNum;
int mNum;
//constructor
public:
Item( string item,int mNum, int meshNum ){
this->item=item;
this-> mNum= mNum;
this-> meshNum= meshNum;
}
//Memeber functions
public:
string getItem(){
return item;
}
void setItem(string item){
this->item = item;
}
int getMeshNum(){
return this->meshNum;
}
void setMeshNum(int meshNum){
this->meshNum= meshNum;
}
int getMNum(){
return this->mNum;
}
void setMNum(int mNum){
this-> mNum= mNum;
}
};
//____________________________________________
class materialList{
// Access specifer
private:
list <Item> items;
//constructor
public:
/* materialList(){
this->items = new list<Item>;
} */
// Memeber fucntions
public:
void add(Item &item)
{
items.push_back(item);
}
//print my list
void Print()
{
ofstream outdata; // outdata is like cin
outdata.open("example2.dat"); // opens the file
if( !outdata ) { // file couldn't be opened
cerr << "Error: file could not be opened" << endl;
exit(1);
}
for (auto &i : items)
outdata << i.getItem() << " "<<i.getMeshNum()<< " "<<i.getMNum()<<endl;
outdata.close();
}
void search(ifstream& inFile){ //this function is where I need help on =<
string line,word;
int materialNum;
istringstream iss;
cout<< "Enter a material number:";
cin>>materialNum;
int**arr= (int**)malloc(20*sizeof(int*));
int i=0;
while(!inFile.eof()){
// read line by line from the file
getline(inFile,line);
if(inFile.good()){
// read word by word in line and place words in arr
iss.clear(); // clear out state
iss.str(line);
iss>> word;
arr[i]=word;
}
if (word==cin){
cout>>line;
}
}
}
};
int main(){
bool value = true;
string objectName;
int Mnum;
int Meshnum;
materialList ml; //(list<Item> test);
while(value){
cout<< "Enter Object name: ";
cin>> objectName;
cout<<" Enter M#: ";
cin>> Mnum;
cout<<"Enter Mesh#: ";
cin>> Meshnum;
//Item second= Item(objectName,Mnum,Meshnum);
ml.add(Item(objectName,Mnum,Meshnum));
ml.Print();
}
//Item test= Item("door",34,50);
//itemList =
//ml.add(test);
//ml.Print();
}
Errors:
material_characterizationf.cpp:105:20: error: assigning to 'int *' from incompatible type 'std::__1::string' (aka 'basic_string<char, char_traits<char>, allocator<char> >')
arr[i]=word;
^~~~
material_characterizationf.cpp:134:17: error: non-const lvalue reference to type 'Item' cannot bind to a temporary of type 'Item'
ml.add(Item(objectName,Mnum,Meshnum));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I know the first error comes from my failed attempts, but I have no idea where the second error came from. The code was working fine until I tried to add a search function.

In your search function, I don't think you need to use the arr array as not only does it cause memory leak due to it not being freed at the end of the function but also it doesn't serve any purposes in the function. You can simply parse the first argument of the input lines from the file as int type into the word variable by setting the word variable as int type instead of string.
That way you can use word to check if it is equal to the materialNum (not equal to cin in your original code as it is an istream object and can't be compared with an integer) input by the user at line (cin >> materialNum;). If word is equal to materialNum, then you can print out the file line using out << line << ends;.
void search(ifstream& inFile){
string line;
int word;
int materialNum;
istringstream iss;
cout << "Enter a material number:";
cin >> materialNum;
int i=0;
while(!inFile.eof()){
// read line by line from the file
getline(inFile,line);
if(inFile.good()){
// read word by word in line and place words in arr
iss.clear(); // clear out state
iss.str(line);
iss >> word;
}
if (word == materialNum){
cout << line << endl;
}
}
}
Update: If you know the file name, you can create a ifstream object (inFile) to open it, and then pass it as an argument to your search function. For example, you can do something like this in your main function
string filename = "example2.dat";
ifstream inFile;
inFile.open(filename, std::ifstream::in);
ml.search(inFile);

Related

replacing string based on user input c++

i want to receive an input from user and search a file for that input. when i found a line that includes that specific word, i want to print it and get another input to change a part of that line based on second user input with third user input. (I'm writing a hospital management app and this is a part of project that patients and edit their document).
i completed 90 percent of the project but i don't know how to replace it. check out following code:
#include <iostream>
#include <stream>
#include <string.h>
#include <string>
using namespace std;
int main(){
string srch;
string line;
fstream Myfile;
string word, replacement, name;
int counter;
Myfile.open("Patientlist.txt", ios::in|ios::out);
cout << "\nEnter your Name: ";
cin.ignore();
getline(cin, srch);
if(Myfile.is_open())
{
while(getline(Myfile, line)){
if (line.find(srch) != string::npos){
cout << "\nYour details are: \n" << line << endl << "What do you want to change? *type it's word and then type the replacement!*" << endl;
cin >> word >> replacement;
}
// i want to change in here
}
}else
{
cout << "\nSearch Failed... Patient not found!" << endl;
}
Myfile.close();
}
for example my file contains this line ( David , ha , 2002 ) and user wants to change 2002 to 2003
You cannot replace the string directly in the file. You have to:
Write to a temporary file what you read & changed.
Rename the original one (or delete it if you are sure everything went fine).
Rename the temporary file to the original one.
Ideally, the rename part should be done in one step. For instance, you do not want to end up with no file because the original file was deleted but the temporary one was not renamed due to some error - see your OS documentation for this.
Here's an idea:
#include <iostream>
#include <fstream>
#include <string>
#include <cstdio>
using namespace std;
void replace(string& s, const string& old_str, const string& new_str)
{
for (size_t off = 0, found_idx = s.find(old_str, off); found_idx != string::npos; off += new_str.length(), found_idx = s.find(old_str, off))
s.replace(found_idx, old_str.length(), new_str);
}
int main()
{
const char* in_fn = "c:/temp/in.txt";
const char* bak_fn = "c:/temp/in.bak";
const char* tmp_fn = "c:/temp/tmp.txt";
const char* out_fn = "c:/temp/out.txt";
string old_str{ "2002" };
string new_str{ "2003" };
// read, rename, write
{
ifstream in{ in_fn };
if (!in)
return -1; // could not open
ofstream tmp{ tmp_fn };
if (!tmp)
return -2; // could not open
string line;
while (getline(in, line))
{
replace(line, old_str, new_str);
tmp << line << endl;
}
} // in & tmp are closed here
// this should be done in one step
{
remove(bak_fn);
rename(in_fn, bak_fn);
remove(out_fn);
rename(tmp_fn, in_fn);
remove(tmp_fn);
}
return 0;
}
One possible way:
Close the file after you read it into "line" variable, then:
std::replace(0, line.length(), "2002", "2003")
Then overwrite the old file.
Note that std::replace is different from string::replace!!
The header is supposed to be <fstream> rather than <stream>
you can't read and write to a file simultaneously so I have closed the file after reading before reopening the file for writing.
instead of updating text inside the file, your line can be updated and then written to file.
#include <iostream>
#include <fstream>
#include <string.h>
#include <string>
using namespace std;
int main(){
string srch;
string line, line2;
fstream Myfile;
string word, replacement, name;
int counter;
Myfile.open("Patientlist.txt", ios::in);
cout << "\nEnter your Name: ";
cin.ignore();
getline(cin, srch);
if(Myfile.is_open())
{
while(getline(Myfile, line)){
if (line.find(srch) != string::npos){
cout << "\nYour details are: \n" << line << endl << "What do you want to change? *type it's word and then type the replacement!*" << endl;
cin >> word >> replacement;
int index = line.find(word);
if (index != string::npos){
Myfile.close();
Myfile.open("Patientlist.txt", ios::out);
line.replace(index, word.length(), replacement);
Myfile.write(line.data(), line.size());
Myfile.close();
}
}
// i want to change in here
}
}else
{
cout << "\nSearch Failed... Patient not found!" << endl;
}
}

Print User Selected Line

In the program, each line of the text file is read into an array. I need to have the user input a line number, then that line of the text file will be printed. How is this done? Thanks!
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void file()
{
string array[2990];
short loop=0;
string line;
ifstream myfile ("weblog.txt");
if (myfile.is_open())
{
while (! myfile.eof() )
{
getline (myfile,line);
array[loop] = line;
cout << array[loop] << endl;
loop++;
}
myfile.close();
}
else cout << "file not available";
}
int main ()
{
file();
return 0;
}
I am assuming that you wanted to print the line that the user inputs to so for example if user input line 3, then you will print the third line. If that is so, the following will work.
#include<bits/stdc++.h>
using namespace std;
struct OpenFailException : public exception{
const char* what() const throw (){
return "Cannot open file";
}
};
class FileIO{
public:
FileIO(const string& Path,const bool &ToMemory){
_Path = Path;
_File.open(_Path);
_Load = ToMemory;
if(_File.is_open()){
if(ToMemory){
while(!_File.eof()){
string Input;
getline(_File, Input, '\n');
_Memory.push_back(Input);
}
}
}
else{
cout<<"File Err";
exit;
}
}
string Data(const int &Line){
return _Memory[Line - 1];
}
private:
string _Path;
fstream _File;
vector <string> _Memory;
bool _Load;
};
int main(){
FileIO A("CMS.cpp", true);
int Input;
cin>>Input;
cout<<A.Data(Input);
}
you can either turn the array into a global variable or you can simply structure a new class for it. Here, I try to abstract the codes for you.
To take in input from an user, what you can do is use the cin function. Below is the reference website.
http://www.cplusplus.com/reference/iostream/cin/
Using the cin function you can direct the userinput into a variable, and use that variable to access your array.
Here is an example of the code, assuming your result is zero-indexed (i.e. array[0] is equal to line number 0), if you want your index to start at 1 (i.e. array[0] is equal to line number 1), then just do array[lineNum-1]:
int lineNum;
cout << "Please enter a line number";
cin >> lineNum;
cout << array[lineNum];

How to check if a specific integer value input from keyboard exist in a line or more lines of a file in C++

I have a small project for a C++ course and I'm stuck trying to check if a value of a data member of STUDENT's class exists in the file(the "ID"). I've tried to use some function that I found on the internet to transform the integer value I'm searching for into a string and then use the find function, to search for it in each line of the file.
It works, but whenever I check one line from the file, it gets false pozitive, because the ID value(for example "12") is for example, identical to the value of age(also "12"). It does that because the age value comes before the ID value in my file and also in the string variable (and I can't change it). I don't know to search in the string for the value of ID only. I use the function "inputInfo" to input student1's member values from the keyboard, and function "checkID" to check if value of "ID" already exists in the file. Also, for another aspect of the project, I am seeking a way to search for occurrence of the ID and name data members values in the same file(once they are already written). One solution I've thought is to somehow start the search after the occurence of another character(for example the space character, given the fact that in the file, each field is delimited from another with a space), but I'm not sure the find function is able to do that.Thank you in advance for your help.Below is a part of the project's code in C++:
#include<iostream>
#include<string>
#include<fstream>
#include <sstream>
using namespace std;
int checkID(int idNumber)
{
string findID;
stringstream id_string;
id_string << idNumber;
findID = id_string.str();
int offset;
ifstream in;
in.open("Students.txt");
if(in.is_open())
{
string line;
while(getline(in, line))
{
if(offset = line.find(findID, 0)!= string::npos)
{
cout<<"The ID already exists. Insert a different ID!"<<endl;
return 0;
}
}
}
else
cout<<"File doesn't exist!"<<endl;
in.close();
}
class PERSON
{
protected:
string name;
string surname;
unsigned int age;
public:
void inputinfo()
{
cin>>name;
cin>>surname;
cin>>age;
}
outputinfo()
{
cout<<name<<endl;
cout<<surname<<endl;
cout<<age<<endl;
}
};
class STUDENT: public PERSON
{
int ID;
float marks_sum;
string belonging_class;
public:
inputInfo()
{
cout<<"Name:";
cin>>name;
cout<<"Surname:";
cin>>surname;
cout<<"Age:";
cin>>age;
do
{
cout<<"ID:";
cin>>ID;
}
while (checkID(ID)==0);
cout<<"Sum of marks:";
cin>>marks_sum;
cout<<"The belonging class:";
cin>>belonging_class;
}
void outputInfo()
{
cout<<name<<endl;
cout<<surname<<endl;
cout<<age<<endl;
cout<<ID<<endl;
cout<<marks_sum<<endl;
cout<<belonging_class<<endl;
}
friend std::ostream& operator << (std::ostream& os, const STUDENT& value )
{
os << value.name<<" "<<value.surname<<" "<<value.age<<" "<<value.ID<<" "<<value.marks_sum<<" "<<value.belonging_class<<std::endl;
return os;
}
};
STUDENT student1;
int writeInFile(STUDENT studentx)
{
ofstream os("Students.txt", ofstream::app);
os << studentx;
os.close();
}
int main()
{
int opt1, opt2;
char option;
do
{
cout<<"1 - Input data into file"<<endl<<"2 - Close program"<<endl;
cin>>opt1;
switch(opt1)
{
case 1:
do
{
cout<<endl;
cout<<"Choose one of variants"<<endl<<"1.Students"<<endl<<"2.Get back to main menu"<<endl;
cin>>opt2;
switch(opt2)
{
case 1:
do
{
cout<<"Do you wish to introduce a new student(Y/N)?";
cin>>option;
if(option!='N')
{
student1.inputInfo();
writeInFile(student1);
}
}
while (option!='N');
break;
}
}
while(opt2!=2);
break;
}
}
while(opt1!=2);
}
#include <sstream>
using namespace std;
bool isUniqueID(ifstream& file, int id)
{
string id_string = to_string(id);
string currently_read_line;
// The position of the searched key. So, in this case,
// only the 3rd value will be tested (starting from 0).
// John Doe 23 456
// | | | |
// 0 1 2 3 (the id)
int offset = 3;
while (getline(file, currently_read_line))
{
istringstream ss(currently_read_line);
string current_entry;
int counter = 0;
while (ss >> current_entry) {
if (current_entry == id_string && counter == offset) {
cout << "The Id already exists." << endl;
return false;
}
counter++;
}
}
// No match found
cout << "The ID does not exist yet." << endl;
return true;
}
Please note:
Just pass your opened file to the function. The file is opened once, instead of opening it every time you want to check an ID.
This requires to compile in -std=c++11 (for the to_string conversion)
[Update]
The offset variable tells the function what value to test for. A more consistent way to do this, would be to format the data as to have a key/value for each student entry. It works as it though.

Reading several types of data into arrays

I am having a tough time figuring out the process of reading text files into the program. Down in the get_answer_key_array, I am trying to read and put only the top line of the text file into an array.
The text file looks something like this:
ABDBCBDBABABCBABCB
Bob Bobby adcad abcbd bacb
Every text file tested in this program will have the answer key on the first line. Every line after the first line will have the persons first name, space, last name, space, grades and missing grades will be replaced by a "-" when I get to it.
I am currently working on obtaining the first line and putting it into the answer key array.
I know that once I am done with the first line I can put the persons first name, last name, and answers into three separate parallel arrays. I am having trouble coming up with the right way to check for that first new line so I can get the answer key.
Alright so now I have changed my get_answer_key_array to obtain all of the arrays I will need. Currently I am trying to get the top line (the answer key) into the first array of answer_key[]. I have tried to implement the getline function but am trying to figure out how to only get the top line. Is it possible to keep my eof() loop yet stop at the first endline to transferthe data of the first line into the array? Also my
answer_key[i] = key; needs changed to something else I bet!
I should also mention once I figure out how to get the top line into an array, I want to use this process to get the rest of the data (names and answers) into their own separate arrays via the following workflow:
in_stream >> first_name[i] >> last_name[i] >> answers[i];
while(!in_stream.eof() ) {
i++;
in_stream >> first_name[i] >> last_name[i] >> answers[i];
}
in_stream.close();
START OF PROGRAM BELOW
void get_input_file(ifstream &in_stream); //gets the text file name from the user
void get_arrays(ifstream &in_stream, int answer_key[], string first_name[], string last_name[], int answers[], int &count); //brings the data from text file into all of the parallel arrays
//void score_grader(int &target, string first_name[], string last_name[], int answers[], int &count, int &score);
//void letter_grade(int &score, int &letter_grade);
//void student_report(int &target, string first_name[], string last_name[], int answers []);
int main()
{
ifstream in_stream;
int answer_key[30], count = 0, score = 0; //initializing the answer key array up to 30 answers
string first_name[20]; //initializing the first name array
string last_name[20]; //initializing the last name array
int answers[30]; //initializing the answers array
cout << "Welcome to the Test Grader." << endl; //welcome message
get_input_file(in_stream); //function call to get the file name
get_arrays(in_stream, answer_key, first_name, last_name, answers, count); //function call to create the arrays
}
void get_input_file(ifstream &in_stream) {
string file_name; //initializing the file name string
do {
cout << "Enter the file name you would like to import the data from: " << endl; //asks user to input name of file
cin >> file_name; //user types name of file
in_stream.open(file_name.c_str()); //program opens the stream
if(in_stream.fail()) {
cout << "Error finding file, try again.\n"; //if failed, asks user for file name again
continue; //continues back to the do loop
}
break;
} while(true);
cout << "File Obtained: " << file_name << endl; //alerts user of file success with printed name
}
void get_arrays(ifstream &in_stream, int answer_key[], string first_name[], string last_name[], int answers[],
int &count) {
int i = 0;
string key; //This will be the storage variable for the first line of text file
if (in_stream.is_open() ) { //if the stream is open
getline(in_stream, key);
cout << "Testing: " << key << endl;
while(!in_stream.eof() ) {
i++;
in_stream >> first_name[i] >> last_name[i] >> answers[i];
}
}
cout << first_name[1] << " " << last_name[1] << " " << answers[1] << endl;
in_stream.close();
}
You can simply read the first line this way
void get_answer_key_array(ifstream &in_stream, char *answer_key, int &count) {
in_stream >> answer_key;
count = strlen(answer_key);
}
The answer_key array must be of type char.
And the endline character is '\n' not '/n'

How to get the whole line where a given word is and store it in a variable?

i am a beginner in the C++ world, i need to get the whole line where a given word is and store it into a variable.
my TXt file has this structure :
clients.txt
085958485 Roland Spellman rolandl#gmail.com
090545874 KATHLEEN spellman kathleen1#hotmail.com
056688741 Gabrielle Solis desperate#aol.com
so the program requests to the user to enter the id of the person, the id is always the first number or word in the line.
the user enters then
090545874
the program has to be able to find the 090545874 in the text file and then get the whole line where it is stored into a variable.
i know how to find a word in a text file but i don't know how to get the whole line into a variable. so at the end my variable has to store
variable = 090545874 KATHLEEN spellman kathleen1#hotmail.com 4878554
after that, i am able to delete the entire line or record.
i use this code to enter the data into the txt file
struct person{
char id[10];
char name[20];
char lastname[20];
char email[10];
} clientdata;
ofstream clientsfile;
clientsfile.open ("clientes.dat" , ios::out | ios::app);
if (clientsfile.is_open())
{
cout<<" ENTER THE ID"<<endl;
cin>>clientdata.id;
clientsfile<<clientdata.id<<" ";
cout<<" ENTER THE NAME"<<endl;
cin>>datoscliente.name;
clientsfile<<clientdata.name<<" ";
cout<<" ENTER THE LAST NAME"<<endl;
cin>>clientdata.lastname;
clientsfile<<clientdata.lastname<<" ";
cout<<" ENTER THE LAST EMAIL"<<endl;
cin>>clientdata.email;
clientsfile<<clientdata.email<<" ";
then i request to the eu to enter the id
and what i need to do is not to find the id only, it's to get the whole line where the id is
so if the user enters 090545874 , i need to find it in the text file , but i need to get teh whole line in this case 090545874 KATHLEEN spellman kathleen1#hotmail.com
so i need to store that into a new variable
string newvariable;
newvariable = 090545874 KATHLEEN spellman kathleen1#hotmail.com
To read files one line at a time, you can use the std::getline function defined in the <string> header (I'm assuming you're using the fstream library as well):
#include <fstream>
#include <string>
int main(int argc, char** argv) {
std::ifstream input_file("file.txt");
std::string line;
while (true) {
std::getline(input_file, line);
if (input_file.fail())
break;
// process line now
}
return 0;
}
What's nice about the function std::getline, though, is that it allows for this much cleaner syntax:
#include <fstream>
#include <string>
int main(int argc, char** argv) {
std::ifstream input_file("file.txt");
std::string line;
while (std::getline(input_file, line)) {
// process line now
}
return 0;
}
thank all of you for your answers, I finally figured it out , I used this function :
bool mostshow(int option, string id)
{
if (option== 2 && id== id1)
return true;
if (option== 3 && id== id1)
return true;
return false;
}
and this other one
void showline(string field1, string field2, string field3, string field4, string field5, string field6, string field7)
{
string store;
store = field1+" "+field2+" "+field3+" "+field4+" "+field5+" "+field6+" "+field7;
cout<<endl;
}
and then in the main
ifstream myfile("clients.dat", ios::in);
if (!myfile)
{
cerr <<" CANNOT OPEN THE FILE!!"<<endl;
exit(1);
}
option=2;
myfile >> field1 >> field2 >> field3 >> field4 >>field5 >> field6 >> field7;
while (!myfile.eof())
{
if (mostshow(option, id))
{
showline(field1, field2, field3, field4, field5, field6, field7);
}
myfile >> field1 >> field1 >> field1 >> field1 >>field1 >> field1 >> field1;
}
myfile.close();
option variable is part of a switch statement which asks if you want to delete or modify the record, 2 means modify , 3 delete
You didn't say how you're reading the file, but the fgets function will do what you want.
Use ifstream, getline and unordered_map:
#include <fstream>
#include <string>
#include <sstream>
#include <exception>
#include <unordered_map>
using namespace std;
ifstream infile("mytextfile.txt");
if (!infile) {
cerr << "Failure, cannot open file";
cin.get();
return 0;
}
unordered_map<string, string> id2line;
string id, line;
while (getline(infile, line)) {
stringstream strstm(line);
strstm >> id;
id2line[id] = line;
}
Now you can do
cout << "Please enter an id: " << endl;
string id;
cin >> id;
try {
// unordered_map::at throws an std::out_of_range exception when the key doesn't exist
string line = id2line.at(id);
cout << "Info:\n " << line << endl;
} catch (out_of_range& e) {
cout << "No information by that id." << endl;
}
You could create a structure and have the structure read in its data by overloading the stream extraction operator:
struct Record
{
unsigned int id;
std::string first_name;
std::string last_name;
std::string email_addr;
friend std::istream& operator>>(std::istream& input, Record& r);
};
std::istream& operator>>(std::istream& input, Record&r)
{
input >> r.id;
input >> r.first_name;
input >> r.last_name;
getline(input, r.email_addr);
return input;
}
Edit 1:
Usage:
ifstream input_file("mydata.text");
Record r;
std::map<unsigned int, Record> container;
while (input_file >> r)
{
unsigned int id = r.id;
container[id] = r;
}
As far as storage is concerned look up the std::map structure and copy the ID field and use it as the key.
I still suggest that this work is a better candidate for a database or spreadsheet.