I am using getline to read up to end of newline but c++ getline gets me stuff till space,
I have txt file data as
address(tab char)1420 Happy Lane
When I do
getline(reader, ss, '\t') I get address in ss string.
when I do getline(reader, ss, '\n') I just get 1420.
I want full "1420 Happy Lane", How to get it ?
Thanks.
#include <fstream>
#include <string>
#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
int main( int argc, char *argv[] )
{
if( argc < 2 )
{
cout << "Missing filename as first argument" << "\n";
exit(2);
}
vector<string> myvector;
string ss;
int i=0, j=0;
ifstream reader(argv[1]);
if (! reader )
{
cout << "Error opening input file : " << " " << argv[1] << '\n';
return -1;
}
while( !reader.eof())
{
if ((i+1) % 2 == 0 )
getline(reader, ss, '\n');
else
getline(reader, ss, '\t');
if (ss[0] == '#')
{
//Skip
getline(reader,ss, '\n');i=0;
continue;
}
i++;
myvector.push_back(ss);
}
reader.close();
vector<string>::iterator it;
stringstream stream;
int vecloc=1;
string tag;
string sData;
cout << "myvector contains: \n";
for ( it=myvector.begin() ; it < myvector.end(); it++ )
{
switch (vecloc)
{
case 1: stream << *it; stream >> tag; vecloc++;break;
case 2:
stream << *it; stream >> sData;
// Do job
cout << tag << " " << sData << "\n";
// Reset.
vecloc=1; break;
default : break;
}
// Clear String stream
stream.str(""); stream.clear();
}
return(0);
}
output
/home/sr/utl
cat abc.txt
hey c++ making me nuts.
/home/sr/utl
a.out abc.txt
myvector contains:
hey c++
Paste the actual code from your editor and double check that there isn't a newline (or maybe other unexpected non-printing characters) in your data file.
This works as expected here:
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
stringstream reader("address\t1420 Happy Lane\n");
string ss;
getline(reader, ss, '\t');
cout << "1: " << ss << endl;
getline(reader, ss, '\n');
cout << "2: " << ss << endl;
}
Output:
1: address
2: 1420 Happy Lane
I got a split() function you can use for that. Use \t as the delimeter:
void split(std::string &string, std::vector<std::string> &tokens, const char &delim) {
std::string ea;
std::stringstream stream(string);
while(getline(stream, ea, delim))
tokens.push_back(ea);
}
You're trying to alternate between grabbing up until a \t and grabbing up until a \n. But the times that you find a '#' comment line throw off your alternation.
By far the easiest and most robust way to handle this sort of thing is to read each line first, and then re-parse the line.
Related
I'm working on a problem where I need to have user input a message then replace the work "see" with "c". I wanted to read in the array message[200] and then break it down into individule words. I tried a for loop but when I concatinate it just adds the privous words. I am only to use array of characters, no strings.
const int MAX_SIZE = 200;
int main(){
char message[MAX_SIZE]; //message array the user will enter
int length; // count of message lenght
int counter, i, j; //counters for loops
char updateMessage[MAX_SIZE]; //message after txt update
//prompt user to
cout << "Please type a sentence" << endl;
cin.get(message, MAX_SIZE, '\n');
cin.ignore(100, '\n');
length = strlen(message);
//Lower all characters
for( i = 0; i < length; ++i)
{
message[i] = tolower(message[i]);
//echo back sentence
cout << "You typed: " << message << endl;
cout << "Your message length is " << length << endl;
for( counter = 0; counter <= length; ++counter)
{
updateMessage[counter] = message[counter];
if(isspace(message[counter]) || message[counter] == '\0')
{
cout << "Space Found" << endl;
cout << updateMessage << endl;
cout << updateMessage << " ** " << endl;
}
}
return 0;
}
After each space is found I would like to output one work each only.
You should really try to learn some modern C++ and standard library features, so you don't end up writing C code in C++. As an example, this is how a C++14 program makes use of standard algorithms from the library to do the job in 10-15 lines of code:
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main()
{
using namespace std::string_literals;
std::istringstream input("Hello I see you, now you see me");
std::string str;
// get the input from the stream (use std::cin if you read from console)
std::getline(input, str);
// tokenize
std::vector<std::string> words;
std::istringstream ss(str);
for(std::string word ; ss >> word; words.push_back(word));
// replace
std::replace(words.begin(), words.end(), "see"s, "c"s);
// flatten back to a string from the tokens
str.clear();
for(auto& elem: words)
{
str += elem + ' ';
}
// display the final string
std::cout << str;
}
Live on Coliru
This is not the most efficient way of doing it, as you can perform replacement in place, but the code is clear and if you don't need to save every bit of CPU cycles it performs decently.
Below is a solution that avoids the std::vector and performs the replacement in place:
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main()
{
std::istringstream input("Hello I see you, now you see me");
std::string str;
// get the input from the stream (use std::cin if you read from console)
std::getline(input, str);
// tokenize and replace in place
std::istringstream ss(str);
std::string word;
str.clear();
while (ss >> word)
{
if (word == "see")
str += std::string("c") + ' ';
else
str += word + ' ';
}
// display the final string
std::cout << str;
}
Live on Coliru
I've read the lines from a textfile and i want to check if that line contains the $ sign.
That's what i got so far:
int main() {
ifstream data_store;
string line;
data_store.open("c:\\test.txt");
while (!data_store.eof())
{
getline(data_store, line);
if (line.find("$"))
cout << "1: " << line << endl;
}
data_store.close();
system("PAUSE");
return 0;
}
Furthermore how can i output them to a file ?
To check if a line contains something using std::string::find to need to check the returned value from find to make sure it is a valid return. To do that we compare it against std::string::npos as that is what find() will return if it does not find anything. This is the reason it finds every line as std::string::npos is still considered true when evaluated as a bool. So refactoring your code you would have:
while (getline(data_store, line))
{
if (line.find("$") != std::string::npos)
cout << "1: " << line << endl;
}
I also changed the while loop as using eof is not how to control a while loop. for more information on that see Why is “while ( !feof (file) )” always wrong?
As far as outputting the string to a file see: How to write std::string to file?
It's a minor thing, but a variant of #NathanOliver's solution, is to use a for loop:
ifstream data_store("c:\\test.txt");
for ( string line; getline(data_store, line); ) {
if ( line.find("$") != string::npos )
cout << "1: " << line << endl;
}
// ...
The benefit here is that line is now local only to the loop, which is what it should be since that is the only place it is used.
I did it yesterday forgot to update.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
bool contains_number(const string &c);
int main()
{
int count = 0;
{
string line1[100];
ifstream myfile("D:/Users/Jarvan/Desktop/test.txt");
int a = 0;
if (!myfile)
{
cout << "Error opening output file" << endl;
system("pause");
return -1;
}
while (!myfile.eof())
{
getline(myfile, line1[a], '\n');
if (contains_number(line1[a]))
{
count += 1;
cout << line1[a] << "\n";
}
else cout << "\n";
}
}
cout << count <<endl;
system("pause");
return 0;
}
bool contains_number(const string &c)
{
return (c.find_first_of("$") != string::npos);
}
I have a file of format as:
2
3 4
7 8 9
10 20 22 02
...
basically numbers in each line , separated by spaces.
I have to read from the file, extract all numbers and maintain their line number too, as I have to make a tree later. I'm doing this to take input, but getting weird outputs.
#include<cstdio>
#include<iostream>
#include<cctype>
using namespace std;
void input()
{
char c,p;
while(c=getchar()!=EOF)
{
if(c=='\n') printf("},\n{");
else if(c==' ') printf(",");
else if(c=='0')
{
p=getchar();
if(p==' ')
{
printf("%c%c,",c,p);
}
else
{
printf("%c,",p);
}
}
else if(isalpha(c))
{
printf("%c",c);
}
}
}
int main()
{
input();
}
The image shows the input and output
You are writing more C than C++.
In C++ you can use streams. Use peek() to check the next character, and >> to actually read it.
E.g.:
using namespace std;
int main(){
ifstream s("/tmp/input");
int nr;
while (!s.eof()) {
switch (s.peek()){
case '\n': s.ignore(1); cout << "},\n{"; break;
case '\r': s.ignore(1); break;
case ' ': s.ignore(1); cout << ", "; break;
default: if (s >> nr) cout << nr;
}
}
}
Use a file stream, read line by line and parse each line with a stringstream:
std::ifstream file("filename");
std::string line;
size_t line_number(1);
while ( std::getline(file, line) ) // reads whole lines until no more lines available
{
std::stringstream stream(line);
int tmp;
std::cout << "Numbers in line " << line_number << ":";
while ( stream >> tmp ) // reads integer divided by any whitespace until no more integers available
{
std::cout << " " << tmp;
}
std::cout << "\n";
++line_number;
}
You'll need to include
#include <iostream> // for std::cout
#include <string> // for std::string
#include <fstream> // for std::ifstream
#include <sstream> // for std::stringstream
I'm making a program for my c++ class. Ultimately I want my program to perform a quicksort on a text file of contacts in the following format:
Firstname Secondname Number
Each contact is separated by a new line. I've started by counting the number of lines and using dynamic memory allocation to create an array of structs which has the same size as the number of lines.
However, when I tried to read in the information from the text file and output it to the screen, all I get is gibberish. I've had a look around on the internet to try and find a solution but everything I've found seems to use a different syntax to me.
Here's my code so far:
#include <iostream>
#include <fstream>
#include <istream>
char in[20];
char out[20];
using namespace std;
struct contact
{
char firstName[14];
char surName[14];
char number[9];
};
//structure definition
int main(void){
cout << "Please enter the input filename: " << endl;
cin >> in;
ifstream input(in);
if(!input){
cerr << "failed to open input file " << in << endl;
exit(1);
}
cout << "Please enter tne output filename: " << endl;
cin >> out;
// read in the input and output filenames
char a;
int b=0;
while (input.good ())
{
a=input.get ();
if (a=='\n')
{
b++;
}
}
// count the number of lines in the input file
input.seekg (0, ios::beg);
//rewind to beginning of file
contact* list = new contact[b];
//dynamically create memory space for array of contacts
int i = 0.;
while(input){
if(i >= b) break;
if(input >> *list[i].firstName >> *list[i].surName >> *list[i].number) i++;
else break;
}
input.close();
//read information from input file into array of contacts
for(int N = 0; N < b; N++){
cout << list[N].firstName << list[N].surName << list[N].number << endl;
}
ofstream output(out);
int k = 0;
for(int k = 0; k<b; k++){
output << list[k].firstName << " " << list[k].surName << " " << list[k].number << endl;
}
//print out the unsorted list to screen and write to output file
//i've done both here just to check, won't print to screen in final version
output.close();
delete []list;
} // end of main()
You reset the files location to the beginning, but the files eofbit is still labeled as true from when you first read the amount of lines. A quick fix to this is re-opening the file after you read the lines, possibly making the line count a function to clean up code.
int lines(const string path)
{
ifstream tmp(path.c_str());
string temp;
int count = 0;
getline(inFile,temp);
while(inFile)
{
count++;
getline(inFile,temp);
}
tmp.close();
return count;
}
Okay, I put together a quick and dirty method using newer C++ constructs to get you most of the way there. You're on your own for writing to the file (trivial) and the quicksort, though I've put the struct into a vector for you, so sorting the vector is as easy as writing a custom function to compare one struct vs the other. I apologize in advance if some of the code is less than canonical C++. I'm way past my bed time, and way tired, but this was interesting enough of a problem that I wanted to give it a go. Happy coding!
#include <iostream>
#include <fstream>
#include <istream>
#include <string>
#include <vector>
#include <algorithm>
#include <cctype>
#include <sstream>
using namespace std;
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
std::stringstream ss(s);
std::string item;
while(std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
return split(s, delim, elems);
}
struct contact
{
std::string firstName;
std::string surName;
std::string number;
contact(std::string& fName, std::string& lName, std::string& num) : firstName(fName), surName(lName), number(num) {}
};
//structure definition
char in[20];
char out[20];
int main()
{
std::vector<contact> contacts;
cout << "Please enter the input filename: " << endl;
cin >> in;
ifstream input(in);
if(!input){
cerr << "failed to open input file " << in << endl;
exit(1);
}
cout << "Please enter tne output filename: " << endl;
cin >> out;
std::string sinput;
// read in the input and output filenames
while (input.good ())
{
getline(input, sinput);
vector<string> tokens = split(sinput, ' ');
if (tokens.size() == 3)
{
contact c(tokens[0], tokens[1], tokens[2]);
contacts.push_back(c);
}
}
input.close();
//read information from input file into array of contacts
std::cout << "Outputting from vector..." << std::endl;
for_each(contacts.begin(), contacts.end(), [](contact& c) {
cout << c.firstName << " " << c.surName << " " << c.number << endl;
});
return 0;
}
Also, just want to give credit that the split methods come from this answer on this very site. Cheers!
I have formatted data like the following:
Words 5
AnotherWord 4
SomeWord 6
It's in a text file and I'm using ifstream to read it, but how do I separate the number and the word? The word will only consist of alphabets and there will be certain spaces or tabs between the word and the number, not sure of how many.
Assuming there will not be any whitespace within the "word" (then it will not be actually 1 word), here is a sample of how to read upto end of the file:
std::ifstream file("file.txt");
std::string str;
int i;
while(file >> str >> i)
std::cout << str << ' ' << i << std::endl;
The >> operator is overridden for std::string and uses whitespace as a separator
so
ifstream f("file.txt");
string str;
int i;
while ( !f.eof() )
{
f >> str;
f >> i;
// do work
}
sscanf is good for that:
#include <cstdio>
#include <cstdlib>
int main ()
{
char sentence []="Words 5";
char str [100];
int i;
sscanf (sentence,"%s %*s %d",str,&i);
printf ("%s -> %d\n",str,i);
return EXIT_SUCCESS;
}
It's actually very easy, you can find the reference here
If you are using tabs as delimiters, you can use getline instead and set the delim argument to '\t'.
A longer example would be:
#include <vector>
#include <fstream>
#include <string>
struct Line {
string text;
int number;
};
int main(){
std::ifstream is("myfile.txt");
std::vector<Line> lines;
while (is){
Line line;
std::getline(is, line.text, '\t');
is >> line.number;
if (is){
lines.push_back(line);
}
}
for (std::size_type i = 0 ; i < lines.size() ; ++i){
std::cout << "Line " << i << " text: \"" << lines[i].text
<< "\", number: " << lines[i].number << std::endl;
}
}