I am a young programmer who is trying to learn c++. i have a working csv.file. but i want to search for a specific number assigned to the name and then displays the name of what i'm looking for. i have the file here:
1,Bulbasaur,grass
2,Ivysaur, grass
3,Venusaur, grass
4,Charmander, fire
5,Charmeleon, fire
6,Charizard, fire
7,Squirtle, water
8,Wartortle, water
9,Blastoise, water
Code
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream ip("pokedex.csv");
string pokedexnum[9];
string pokemonName[9];
string pokemonType[9];
cout<<"please enter a pokemon number:"<<" ";
cin>>pokemonType[0];
while (ip.good()){
getline( ip, pokedexnum[0]);
getline( ip, pokemonName[0]);
getline( ip, pokemonType[0]);
}
cout<<"the pokemon that is:"<< " "<<pokedexnum[0]<< "is the pokemon called:"<< pokemonName[0];
ifstream close("pokedex.csv");
return 0;
}
when it runs
please enter a pokemon number: 1
the pokemon that is: is the pokemon called:8,Wartortle, water
could you please point out what i am doing wrong?
Among the issues in this code:
You're not using std::getline correctly for comma-separated data. The result is each pass is consuming three lines from your input file; not three values from each line.
You're also not using ip.good() correctly as a while-condition.
You're retaining your test value in the array, which will be overwritten on the first iteration pass, so it is lost.
You're ignoring potential IO failures with each std::getline invoke.
You're overwriting slot-0 in your arrays with each loop iteration.
Minor, ifstream close("pokedex.csv"); clearly isn't doing what you think it is. That just creates another fstream object called close on the given file name.
The later may be intentional for now, but clearly broken in the near future.
In reality, you don't need arrays for any of this. All you're doing is reading lines, and seem to want to test the input number against that of the CSV data first column, reporting the line that you find, then ending this.
So do that:
Read the input value to search for.
Open the file for scanning.
Enumerate the file one line at a time.
For each line from (3), use a string stream to break the line into the comma separated values.
Test the id value against the input from (1). If the same, report the result and break the loop; you're done.
The result is something like this:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstdlib>
int main()
{
std::cout<<"please enter a pokemon number: ";
long num;
if (std::cin >> num && num > 0)
{
std::ifstream ip("pokedex.csv");
std::string line;
while (std::getline(ip, line))
{
std::istringstream iss(line);
std::string id, name, skill;
if (std::getline(iss, id, ',') &&
std::getline(iss, name, ',') &&
std::getline(iss, skill))
{
char *endp = nullptr;
long n = std::strtol(id.c_str(), &endp, 10);
if (id.c_str() != endp && n == num)
{
std::cout << "The pokemon that is: " << num << " is called: " << name << '\n';
break;
}
}
}
}
}
Admittedly untested, but it should work.
Whether you want to store the items in arrays at this point is entirely up to you, but it isn't needed to solve the somewhat abstract problem you seem to be attempting, namely finding the matching line and reporting the name from said-same. If you still want to store them in arrays, I suggest you craft a structure to do so, something like:
struct Pokemon
{
int id;
std::string name;
std::string skill;
};
and have a single array of those, rather than three arbitrary arrays that must be kept in sync.
Four issues jump out at me:
You store the user's input into pokemonType, but then also use pokemonType for reading data from your CSV file. The file input is going to overwrite the user input.
Your file input loop always references index 0. All of the lines from your data file are going into element 0. That's the main reason that even if the user inputs 1, the output is from the last line of the data file.
Your file reading loop is structured like you want to put one part of each data line into a different array, but what you've written actually reads three lines on every iteration, storing those lines into the three different arrays.
This isn't affecting your output, but the code ifstream close("pokedex.csv"); is written like you want to close the file stream you opened, but I do believe what this line actually does is create a new ifstream called close, and opens pokedex.csv attached to it. In other words, it's just like your other line ifstream ip("pokedex.csv"); but with close as the variable name instead of ip.
You are going to want to look into something called "string tokenization". Start with some web searches, apply what you read about to your code, and of course if you hit another snag, post a new question here to Stack Overflow, showing (as you did here) what you tried and in what way it isn't working.
Elaborating on #3, here's what how your data file is being read:
at the end of the 1st iteration of the file-reading loop, ...
pokedexnum[0] is "1,Bulbasaur,grass"
pokemonName[0] is "2,Ivysaur, grass"
pokemonType[0] is "3,Venusaur, grass"
at the end of the 2nd iteration of the file-reading loop, ...
pokedexnum[0] is "4,Charmander, fire"
pokemonName[0] is "5,Charmeleon, fire"
pokemonType[0] is "6,Charizard, fire"
at the end of the 3rd iteration of the file-reading loop, ...
pokedexnum[0] is "7,Squirtle, water"
pokemonName[0] is "8,Wartortle, water"
pokemonType[0] is "9,Blastoise, water"
And that's why
<< "is the pokemon called:"<< pokemonName[0];
outputs
is the pokemon called:8,Wartortle, water
I am working on a two-part project for a class, and have finished the first section but have run into trouble on the second part. For the first part, I was able to read a list from a file and into a vector to manipulate with various functions. A list from this section would look like:
banana
apple
pineapple
grapefruit
orange
pear
grape
lime
lemon
Which I was able to complete. For this first part, I simply have a vector of strings. However, the second part introduces a quantity to these values. The list for this section would follow as:
foo 5
bar 4
baz 2
boz 1
foo 3
At this point, I'm not sure how to read for item as a string and a corresponding int which follows it. For items that are repeated, they're supposed to be add to the original value for that item. I was planning on having a vector of objects which had a name and a quantity to manipulate but I need to read the file first. Thanks for any help!
This is how I was originally reading the file
if (fileIn.is_open()){
//file opened successfully so we are here
ifstream inf(fileName + ".txt");
string word;
while (inf >> word)
{
currentSet.push_back(word);
}
Just do something like:
map<string, int> vals; //or some other data structure
ifstream ifs(somefile);
string word;
int i;
while(ifs >> word >> i) {
vals[word] += i;
}
Simply read them one after the other. Of course you can add error checking as you want. But I recommend the map data structure for easy access and manipulation.
I am new to file-handling...
I am writing a program that saves data in text-files in the following format:
3740541120991
Syed Waqas Ali
Rawalpindi
Lahore
12-12-2012
23:24
1
1
(Sorry for the bad alignment, it's NOT a part of the program)
Now I'm writing a delete function for the program that would delete a record.
So far this is my code:
void masterSystem::cancelReservation()
{
string line;
string searchfor = "3740541120991";
int i=0;
ifstream myfile("records.txt");
while (getline(myfile, line))
{
cout << line << endl;
if (line==searchfor)
{
// DELETE THIS + THE NEXT 8 LINES
}
}
}
I've done a bit of research and have found out that there is no easy way to access the line of a text file so we have to create another text file.
But the problem arises that how do I COPY the records/data before the record being deleted into the NEW text file?
Open the input file; read one line at a time from the input file. If you decide to want to keep that line, write it to the output file. On the other hand, if you want to 'delete' that line, don't write it to the output file.
You could have a record per line and make even more easy for example:
3740541120991|Syed Waqas Ali|Rawalpindi|Lahore|12-12-2012|23:24|1|1
and the | character saparating each field. This is a well known technic knows as CSV (Comma separated Values)
This way you don't have to worry about reading consecutive lines for erase a record and add a record access the file only once.
So your code becoms into:
void masterSystem::cancelReservation()
{
string line;
string searchfor = "3740541120991";
ifstream myfile("records.txt");
while (getline(myfile, line))
{
// Here each line is a record
// You only hace to decide if you will copy
// this line to the ouput file or not.
}
}
Don't think only about removing a record, there are others operations you will need to do against this file save a new record, read into memory and search.
Think a moment about search, and having your current desing in mind, try to answer this: How many reservations exists for date 12-12-2012 and past 12:00 AM?
In your code you have to access the file 8 times per record even if the other data is irrelevant to the question. But, if you have each record in a line you only have to access file 1 time per record.
With a few reservations the diference is near 0, but it grows exponentially (n^8).
so this is my first time posting a question here so please bear with me. I am studying computer science for my bachelors, and I would like some help. We have created various Classes that are all part of a Roster Management System. I have all the classes set up and such, and I can figure out how to store everything in a dynamically allocated array later on, for the time being I am having a difficult time just reading the data needed from a file.
The format for the text file is as follows:
course1-name | course1-code | number-credits | professor-name
student1 first name | student1 last name|credits|gpa|mm/dd/yyyy|mm/dd/yyyy
student2 first name | student2 last name|credits|gpa|mm/dd/yyyy|mm/dd/yyyy
end_roster|
course2-name | course2-code | number-credits | professor-name
student1 first name | student1 last name|credits|gpa|mm/dd/yyyy|mm/dd/yyyy
end_roster|
As you can see, the rosters only have four data fields, course name, course code, number of credits and the professors name.
Students have 6 fields, 7 if you include the end_roster marker (the end_roster marker is literally just that, not a bool value or anything.
Anyway, I cant seem to figure out how to read this input properly. I can read it all in and tokenize it, but then I don't know how to append each "section" to its correct class. This happens to give me each "token" (not 100% clear what that is, but it seems to append each set of characters into a string). I do not know how to assign it into their proper places from this point forward though.
ifstream myroster("rosters.txt");
while( ! myroster.eof() )
{
getline(myroster, line);
cout << line << endl << endl;
char c[line.length() + 1];
strcpy (c, line.c_str());
char * p = strtok(c, "|");
while (p != 0)
{
cout << p << endl;
p = strtok(NULL, "|");
counter++;
}
}
myroster.close();
I've also tried the following;
ifstream myroster("rosters.txt");
while (!myroster.eof())
{
getline(myroster, line, '|');
counter++;
}
Both methods had some form of counter implementation (my first attempt). For example; if counter == 4 it'll be appended to roster, or counter == 6 and its students, but nothing worked (I realized the flaw later on)
The reason I don't just hardcode the program to implement line one for roster1 information, line 2 for student 1, line 3 for student 2, and etc is because the data needs to be edited in the program, and one of the options is to add students/remove them and add rosters/remove them, after which the file needs to be updated again, and then read in again after.
Can anyone shed some light on this?
How do i find a string in a file? In my code, i want to find the name of a person in the file. and do the actions in the comments. Here is my code:
int main(){
size_t found;
ofstream myfile;
cout << "Enter the name you wish to delete." << endl;
getline(cin, name);
myfile.open("database.dat");
found=myfile.find(name);
if (found!=string::npos){
number = myfile.tellg();
/*Delete current line and next line*/
}
}
Do you want to modify the file, or simply skip those two lines while reading?
Actually, the solution is the same for both, because removing data from the middle of the file requires reading everything after that and rewriting it with an offset (just like removing an element from the middle of an array).
So, read the entire file into memory except for any lines you determine need to be deleted (just skip those). After that, write the surviving lines back to disk. It's probably a good idea to use a temporary file which gets moved to the original name as a final step, so that data isn't destroyed if your process is aborted.