I am trying to write a very basic program to read in a CSV and display it. The function, as you can see below, is a very basic one. It uses getline to read in each row (until the newline chracter) before displaying each cell. It was working fine and I was finetuning the loop to display each cell when getline simply stopped working. Without changing any of the code to do with getline, I compiled it and it would not read from the file. row is always empty. However, the ifstream is valid because the "test" string (which I inserted in response) reads in from sheet fine. Can anyone help me?
PS: I have had similar problems with getline before. Is it something to do with my system? It seems to work on and off
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
ifstream sheet( "StockTake.csv", ios::app );
if ( ! sheet.is_open() )
{
cout << "Cannot Open File!\n";
return 0;
}
else
{
cout << "Opened File\n";
}
//Now print each row (find the newline chracter at the end of each line)
/*string test;
sheet >> test;
cout << test;*/
for ( string row; ! sheet.eof(); getline(sheet, row, '\n') )
{
if (row == "")
{
cout << "Bad Read. Exiting\n";
return 0;
}
//Print out each row with a tab space between each cell
string cell;
//find the beginning and the end of each cell
for (int i = 0, j = 0; ; )
{
/*Checks if the cell is enclosed in quotes
The first time, j == i hence the -2 and +2
the +2 is required to "skip" out the apostrophes if
they are found*/
if (row.at(i) == '"')
{
i++;
j = i-2;
do
{
j = row.find('"', j+2);
} while (row.at(j+1) == '"');
/*Check for the "" apostrophe sign*/
}
else
{
j = row.find(',', i);
}
/*Print the Cell*/
if (j == string::npos) //if this is the last cell
{
cell = row.substr(i, row.size() - i);
}
else if ( j-i != 0)
{
cell = row.substr(i, j-i);
}
else
{
cell = "";
}
/*Check for the "" apostrophe sign, and replace
with " for each instance*/
if ( cell.find("\"\"", 0) != string::npos )
{
int pos = -2; //must start at zero
do
{
//Skips out the "current" apostrophe
//if there are more than one
pos = cell.find("\"\"", pos+2);
cell = cell.substr(0, pos) +
cell.substr(pos+1, cell.size()- (pos+1) );
} while (cell.find("\"\"", pos+2) != string::npos);
}
/*Display the Cell, only the space will be displayed
if the cell is empty*/
cout << cell << " ";
/*Find the next cell*/
if ( row.at(j) == '"' )
{
i = j+2;
}
else
{
i = j+1;
}
}
cout << "\n"; //Print newline character at the end of each line
}
return 0;
}
Related
I am trying to the beginning of a string and the end. If the word has an uppercase letter we change it to lowercase. If the word has a space or '"' we erase the character. The first recursive call it should check and see that the end of the string has a capital letter and it should change it to lowercase. However when I output word[word.size()] it outputs a blank space, but it I output word[word.size() - 1] it will output the letter that I am looking for. I wasn't sure what the blank space is and how I should handle it as I don't want it in my string because it is causing comparison issues.
bool checkPalindrome(string word){
if (isupper(word[0]))
{
word[0] = tolower(word[0]);
}
if (isupper(word[word.size()]))
{
word[word.size()] = tolower(word[word.size()]);
}
//check if there is a space or "" if there is then delete that position from the string
if (word[0] == ' ' || word[0] == '"')
{
word.erase(1);
}
if (word[word.size()] == ' ' || word[word.size()] == '"')
{
word.pop_back();
}
if (word.size() > 1)
{
if (word[0] == word[word.size()])
{
word = word.substr(1, word.size() - 2);
return checkPalindrome(word, count);
}
else
{
return false;
}
}
else
{
return false;
}
int main()
{
ifstream inFile;
bool check = false;
string temp = "";
int count = 0;
vector<string> vect;
//Reading from a file line by line
inFile.open("words.txt");
if (inFile.is_open())
{
while (getline(inFile, temp))
{
vect.push_back(temp);
}
}
inFile.close();
for (auto i = 0; i < vect.size(); i++)
{
count = vect[i].size();
check = checkPalindrome(vect[1], count);
if (check == true)
{
cout << vect[i] << ", is a palindrome!\n";
}
else
{
cout << vect[i] << ", is not a palindrome.\n";
}
}
} return 0;
If the size of the string is 4, then there are only 4 elements: 0, 1, 2, and 3. There is no fifth element, so you cannot access element number four.
If a string's length is five:
Zero is the first element.
One is the second element.
Two is the third element.
Three is fourth element.
The fifth element is, of course Leeloo, which is not a character in the string. If a string's length is four, you should not attempt to access the fifth element (at least, not without her permission).
Ecto gamat.
I am quite new to c++ programming and data structures and really need some help. I am working on an assignment where I have a text file with 100 lines and on each line there is an item, a status(for sale or wanted), and a price. I need to go through the text file and add lines to an array of structs and as I add lines I need to compare the new information with the previously submitted information. If there is a line that is wanted and has a price higher than a previously input item that is for sale then the item would be removed from the struct and the array of structs shifted.
The place that I am having trouble is in actually shifting all the structs once a line that satisfies the condition is found.
My issue is that when I try to shift the array of structs using the second for loop nothing happens and I just get null structs and nothing seems to move.
Please if you guys can offer any help it would be greatly appreciated.
Below is the code of the text file and my current code.
#include<iostream>
#include<fstream>
#include <string>
#include <algorithm>
#include <sstream>
using namespace std;
struct items
{
string type;
int status;
int price;
} itemArray [100];
int main(int argc, char *argv[]) {
int x = -1;
//int chickenCount = 0;
int counter = 0;
int itemsSold = 0;
int itemsRemoved = 0;
int itemsForSale = 0;
int itemsWanted = 0;
string itemType;
int itemStatus = 0;
int itemPrice = 0;
int match = 0;
ifstream myReadFile( "messageBoard.txt" ) ;
std::string line;
//char output[100];
if (myReadFile.is_open()) {
while (!myReadFile.eof()) {
getline(myReadFile,line); // Saves the line in STRING.
line.erase(std::remove(line.begin(), line.end(), ' '), line.end());
//cout<<line<<endl; // Prints our STRING.
x++;
std::string input = line;
std::istringstream ss(input);
std::string token;
while(std::getline(ss, token, ',')) {
counter++;
//std::cout << token << '\n';
if (counter>3){
counter =1;
}
//cout << x << endl;
if (counter == 1){
itemType = token;
//cout<< itemType<<endl;
}
if (counter == 2){
if (token == "forsale"){
itemStatus = 1;
//itemsForSale++;
}
if (token == "wanted"){
itemStatus = 0;
//itemsWanted++;
}
//cout<< itemStatus<<endl;
}
if (counter == 3){
itemPrice = atoi(token.c_str());
//cout<< itemPrice<<endl;
}
//cout<<"yo"<<endl;
}
if (x >= 0){
for (int i = 0; i<100;i++){
if (itemArray[i].type == itemType){
//cout<<itemType<<endl;
if(itemArray[i].status != itemStatus){
if (itemArray[i].status == 1){
if(itemPrice>=itemArray[i].price){
itemsSold++;
match =1;
//itemArray[i].type = "sold";
for (int j=i; j<100-1;j++){
//cout<<j<<endl;
itemArray[j].type = itemArray[j+1].type;
itemArray[j].status = itemArray[j+1].status;
itemArray[j].price = itemArray[j+1].price;
}
i =i-1;
break;
}
}
if (itemArray[i].status == 0){
if(itemArray[i].price>=itemPrice){
itemsSold++;
match = 1;
//itemArray[i].type = "sold";
for (int j=i; j<100-1;j++){
//cout<<j<<endl;
itemArray[j].type = itemArray[j+1].type;
itemArray[j].status = itemArray[j+1].status;
itemArray[j].price = itemArray[j+1].price;
}
i=i-1;
break;
}
}
}
}
}
}
if (counter == 3 && match == 0){
itemArray[(x)].type = itemType;
itemArray[(x)].status = itemStatus;
itemArray[(x)].price = itemPrice;
}
match = 0;
// cout << itemArray[x].type << " " << itemArray[x].status<<" "<<itemArray[x].price<<endl;
}
for(int i=0;i<100;i++){
cout<<itemArray[i].type<< " "<<itemArray[i].status<<" "<<itemArray[i].price<<endl;
}
//cout<<itemArray[1].price<<endl;
cout << itemsSold<<endl;
}
myReadFile.close();
return 0;
}
text file: https://drive.google.com/file/d/0B8O3izVcHJBzem0wMzA3VHoxNk0/view?usp=sharing
Thanks for the help
I see several issues in the code, but without being able to test it, I think the main problem is that you always insert new elements at position 'x' which correspond to the currently line read from the file, without taking into account any shift of elements done. You should insert the new element at the first empty slot (or just overwrite the old element instead of shifting everything).
An other issue is that you do not initialize the status and price in your array.
The best way would be to rewrite the code by using more standard C++ features, for example:
replace the items structure by a class with a constructor defining default values
use object copy (there is no need to copy a struct element by element)
use standard C++ containers like a list (see http://www.cplusplus.com/reference/list/list/) which has insert and erase methods
I've wrote a program which reads a textfile character for character and counts the amount of vowels that pass. However if a symbol, say "*" appears, I want the program to stop counting the vowels and start counting the non-vowels, obviously continuing from that point forward. I've written a different function and entered the following:
if (kar == '*'){
reversecounting(i);
return 0;
}
Where reversecounting is the int-function counting non-vowels.
The problem I'm having right now is that whenever it does this, the function counting the non-vowels starts at the beginning of the file. Is there a way to make it continu on from the point where the other function stopped?
I'm using the "get"-function to read from the file. Thanks in advance.
Edit: sorry for not including relevant code, I've added it now and some commentary to make it understandable
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
int countnonvowels( int &k ); //prototype
int countvowels( int k ){ //start function to count vowels
ifstream input; //to open textfile
char kar; // this is the character that will be read
int countvowels = 0; //local counter of vowels
input.open ("input.txt",ios::in); //opening the textfile
kar = input.get ( ); //first obtain a character from the textfile
while ( ! input.eof ( ) ) { //reads the file untile end of file
kar = input.get ( ); //the next character in the file gets "read"
if( kar == 'e' or kar == 'a' or kar == 'i' or kar == 'o' or kar == 'u' ){ //checks whether the character is a vowel
countvowels++; //local counter goes up by one
kar = input.get(); //take the next letter and print it
cout << kar << " " << countvowels << endl;
countvowels = 0; //value becomes zero again
}//if
if (kar == '*'){ //if the character is a "*", I want the non-vowels to be counted and the k-th non-vowel to be printed
countnonvowels(k);
return 0; //this function has to stop running
}//if
} // while
input.close ( );
}//countvowels
int countnonvowels(int &k){//counts the non-vowels
ifstream input;
char kar;
int countnonvowels = 0;
input.open ("input.txt",ios::in); //open the file
kar = input.get ( );
while ( ! input.eof ( ) ) { //same while loop
kar = input.get ( );
if( kar != 'e' or kar != 'a' or kar != 'i' or kar != 'o' or kar != 'u' ){ //now i want the counter to roll if it is NOT a vowel
countnonvowels++;
cout << kar << endl;
}
if (kar == '*'){ //if a "*" appears, I want the vowels to be counted again
countvowels(k);
return 0;
}//if
} // while
input.close ( );
}//countnonvowels
int main ( ) {
countvowels(2);
return 0;
} // main
The problem here is that I get an endless loop: The file gets checked for vowels, it see's a [star sign], starts counting the non-vowels from the start of the text, see's the [star sign] again and starts counting the vowels from the start of the textfile etc...
The star-sign (shift+8) makes everything cursive apparently, I hope it's clear which one I mean.
Here is a short example given that you know how to check if the letter is a vowel or not. I'm leaving modifying it to work for a whole file to you since I suspect this is a homework question.
void countLetters(const string& line)
{
int vowels, nonVowels;
vowels = nonVowels = 0;
bool countingVowels = true;
for (int position = 0; position < line.length(); position++)
{
if (countingVowels && isVowel(line[position])
{
vowels++;
}
else if (!countingVowels && !isVowel(line[position]))
{
nonVowels++;
}
else if (line[position] == '*')
{
countingVowels = !countingVowels;
}
}
cout << vowels << " "<< nonVowels<<endl;
}
i need ThE FirsT AnD LasT letter of every word to be uppercase and the rest lowercase but function convertFirstAndLastLetter only does the first and last of the sentence.
void convertFirstAndLastLetter(char wrd[])
{
size_t last = strlen(wrd) - 1;
size_t first = 0;
wrd[first] = toupper(wrd[first]);
wrd[last] = toupper(wrd[last]);
for(int i = first + 1 ; i < last - 1; i++)
{
wrd[i] = tolower(wrd[i]);
}
}
int main ()
{
float val;
cout << "ent ";
cin >> val;
if (val == 4)
{
char wrd[256];
cin.ignore();
cin.getline(wrd,256);
convertFirstAndLastLetter(wrd);
cout << wrd;
return 0;
}
}
Right now you're passing a whole line to your function, so the first and last characters are all that is being changed.
To fix that you need to split the line up into words which could be done by reading a word at a time using std::cin >> word, or reading the whole line and then using a std::stringstream to split it up. Both are about the same, but I used a stringstream.
Next, if I'm reading your statement correctly, you want to have the first and last "letter" of each word uppercase and the rest lowercase. That means we need to find the first and last letter in case there is punctuation before or after the word.
Once the first and last are determined it's easy to uppercase them and lowercase the rest.
#include <iostream>
#include <string>
#include <sstream>
#include <cctype>
void convertFirstAndLastLetter(std::string& word)
{
if(!word.empty())
{
size_t first = 0;
size_t last = word.size() - 1;
//Find first alpha character
while(first < word.size() && !std::isalpha(word[first]))
{
++first;
}
//If the position is valid, uppercase it
if(first < word.size())
{
word[first] = static_cast<char>(std::toupper(word[first]));
}
//Find last alpha character
while(last > first && !std::isalpha(word[last]))
{
--last;
}
//If the position is valid, uppercase it
if(last > first)
{
word[last] = static_cast<char>(std::toupper(word[last]));
}
for(size_t i = first + 1; i < word.size() && i < last; ++i)
{
if(std::isalpha(word[i]))
{
word[i] = static_cast<char>(std::tolower(word[i]));
}
}
}
}
int main()
{
float val;
std::cout << "ent ";
std::cin >> val;
std::cin.ignore();
if(val == 4)
{
std::string line;
if(std::getline(std::cin, line))
{
std::string word;
std::stringstream ss(line);
while(ss >> word)
{
convertFirstAndLastLetter(word);
std::cout << word << " ";
}
std::cout << "\n";
}
}
return 0;
}
Keep in mind this will discard any extra spaces at the beginning and end of each line as well as any extra spaces between words. The way I am printing them out will also add an extra space at the end of each line. You didn't mention any concern about those things in your question, so I didn't worry about them. They are all solvable with a little extra effort.
Now with less duplicated code:
#include <algorithm>
#include <iostream>
#include <string>
template<typename It>
void upperFirstAlpha(It begin, It end)
{
auto first = std::find_if(begin, end, isalpha);
if (first != end)
*first = toupper(*first);
}
int main()
{
for (std::string s; std::cin >> s;) {
std::transform(s.begin(), s.end(), s.begin(), tolower);
upperFirstAlpha(s.begin(), s.end());
upperFirstAlpha(s.rbegin(), s.rend());
std::cout << s << ' ';
}
}
As #Retired Ninja pointed out the first version wouldn't work for punctuation, whether this version is what you are looking for depends on what your input looks like.
This function
void convertFirstAndLastLetter(char wrd[])
{
size_t last = strlen(wrd) - 1;
size_t first = 0;
wrd[first] = toupper(wrd[first]);
wrd[last] = toupper(wrd[last]);
for(int i = first + 1 ; i < last - 1; i++)
{
wrd[i] = tolower(wrd[i]);
}
}
is wrong. For example if character array is empty that is it has only the terminating zero then expression strlen(wrd) - 1 will give you the maximum value for an object of type size_t and in the next statement
wrd[last] = toupper(wrd[last]);
you will try to change memory beyond the array.
Also if you use standard function strlen then you have to include header <cstring>.
In fact there is no any need to use function strlen. The code can be written simpler
#include <cctype>
//...
void convertFirstAndLastLetter( char wrd[] )
{
if ( *wrd )
{
*wrd = std::toupper( *wrd );
if ( *++wrd )
{
while ( *( wrd + 1 ) )
{
*wrd = std::tolower( *wrd );
++wrd;
}
*wrd = std::toupper( *wrd );
}
}
}
#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
void convertFirstAndLastLetter(char wrd[])
{
size_t last = strlen(wrd) - 1;
size_t first = 0;
wrd[first] = toupper(wrd[first]);
wrd[last] = toupper(wrd[last]);
for(int i = first + 1 ; i < last; i++)
{
wrd[i] = tolower(wrd[i]);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
float val;
cout << "ent ";
cin >> val;
if (val == 4)
{
char wrd[256];
cin.ignore();
cin.getline(wrd,256);
convertFirstAndLastLetter(wrd);
cout << wrd;
return 0;
}
}
I want to get the last but not empty line in a txt file.
This is my code:
string line1, line2;
ifstream myfile(argv[1]);
if(myfile.is_open())
{
while( !myfile.eof() )
{
getline(myfile, line1);
if( line1 != "" || line1 != "\t" || line1 != "\n" || !line1.empty() )
line2 = line1;
}
myfile.close();
}
else
cout << "Unable to open file";
The problem is I cannot check the empty line.
Okay, let's start with the obvious part. This: while( !myfile.eof() ) is essentially always wrong, so you're not going to detect the end of the file correctly. Since you're using getline to read the data, you want to check its return value:
while (getline(myfile, line1)) // ...
Likewise, the logic here:
if( line1 != "" || line1 != "\t" || line1 != "\n" || !line1.empty() )
line2 = line1;
...is clearly wrong. I'm guessing you really want && instead of || for this. As it stands, the result is always true, because no matter what value line1 contains, it must be unequal to at least one of those values (i.e., it can't simultaneously contain only a tab and contain only a new-line and contain nothing at all -- but that would be necessary for the result to be false). Testing for both !line1.empty() and line1 != "" appears redundant as well.
Why not read the file backwards? That way you don't have to scan the entire file to accomplish this. Seems like it ought to be possible.
int main(int argc, char **argv)
{
std::cout<<"Opening "<<fn<<std::endl;
std::fstream fin(fn.c_str(), std::ios_base::in);
//go to end
fin.seekg(0, std::ios_base::end);
int currpos = fin.tellg();
//go to 1 before end of file
if(currpos > 0)
{
//collect the chars here...
std::vector<char> chars;
fin.seekg(currpos - 1);
currpos = fin.tellg();
while(currpos > 0)
{
char c = fin.get();
if(!fin.good())
{
break;
}
chars.push_back(c);
currpos -= 1;
fin.seekg(currpos);
}
//do whatever u want with chars...
//this is the reversed order
for(std::vector<char>::size_type i = 0; i < chars.size(); ++i)
{
std::cout<<chars[i];
}
//this is the forward order...
for(std::vector<char>::size_type i = chars.size(); i != 0; --i)
{
std::cout<<chars[i-1];
}
}
return 0;
}
It wouldn't be enough to change your ||'s to &&'s to check if the line is empty. What if there are seven spaces, a tab character, another 3 spaces and finally a newline? You can't list all the ways of getting only whitespace in a line. Instead, check every character in the line to see if it is whitespace.
In this code, is_empty will be false if any non-space character is found in the line.
bool is_empty = true;
for (int i = 0; i < line.size(); i++) {
char ch = line[i];
is_empty = is_empty && isspace(ch);
}
Full solution:
#include <iostream>
#include <fstream>
#include <cctype>
#include <string>
using namespace std;
int main(int argc, char* argv[]) {
string line;
string last_line;
ifstream myfile(argv[1]);
if(myfile.is_open())
{
while( getline(myfile, line) ) {
bool is_empty = true;
for (int i = 0; i < line.size(); i++) {
char ch = line[i];
is_empty = is_empty && isspace(ch);
}
if (!is_empty) {
last_line = line;
}
}
myfile.close();
cout << "Last line: " << last_line << endl;
}
else {
cout << "Unable to open file";
}
return 0;
}
Additional to what the others said:
You can avoid reading whitespace by doing myfile >> std::ws before you call std::getline(). This will consume all leading whitespaces.
Then your condition reduces to !line1.empty(). This would also work when the line contains nothing but several whitespaces, for which your version fails.
I wasn't able to google an appropriate get_last_line function for my needs and here's what i came up with. You can even read multiple non-empty last lines by recalling the instream get_last_line func without resetting the seeker. It supports a 1 char only file. I added the reset parameter, which can be set to ios_base::end to allow output operations after reading the last line(s)
std::string& get_last_line(
std::istream& in_stream,
std::string& output = std::string(),
std::ios_base::seekdir reset = std::ios_base::cur)
{
output.clear();
std::streambuf& buf = *in_stream.rdbuf();
bool text_found = false;
while(buf.pubseekoff(-1, std::ios_base::cur) >= 0)
{
char c = buf.sgetc();
if(!isspace(c))
text_found = true;
if(text_found)
{
if(c == '\n' || c == -1)
break;
output.insert(0, sizeof c, c);
}
}
buf.pubseekoff(0, reset);
return output;
}
std::string& get_last_line(
const std::string& file_name,
std::string& output = std::string())
{
std::ifstream file_in(
file_name.c_str(),
std::ios_base::in | std::ios_base::ate);
if(!file_in.is_open())
{
output.clear();
return output;
}
get_last_line(file_in, output);
file_in.close();
return output;
}