String manipulation and ignoring part of string - c++

I have an input with the following from a text file using C++
command1 5 #Create 5 box
length 12
insertText THIS IS A BOX
how can i read in the input while ignoring anything after the #sign?
for example output should be without #Create 5 box
command1 5
length 12
insertText THIS IS A BOX
EDIT:
I tried the following:
while(getline(myfile, line))
{
istringstream readLine(line);
getline(readLine, command, ' ');
getline(readLine, input, '\0');
}
...but it doesn't seem to work.

The outer while(getline( and istringsteam are good, but after that you'd want to read a space-separated word into command, then perhaps one or more space-separated inputs after that: something like
std::string command, input;
std::vector<std::string> inputs;
if (readLine >> command && command[0] != '#')
{
while (readLine >> input && input[0] != '#')
inputs.push_back(input);
// process command and inputs...
}
It's easier to use >> than getline to parse readLine because they set the stream failure state if they don't get at least one valid character, making the [0] indexing safe and dropping out cleanly for empty lines, or commands with no inputs.

You can simply use std::getline() like this:
int main()
{
std::ifstream ifs("file.txt");
std::string line;
while(std::getline(ifs, line))
{
std::istringstream iss(line);
if(std::getline(iss, line, '#')) // only read up to '#'
{
// use line here
std::cout << line << '\n';
}
}
}
Output:
command1 5
length 12
insertText THIS IS A BOX

in your function where you check every character one by one, add this code: (pseudo code)
if(currChar == #){
while(currChar != '\n'){
getNextChar();// you arent saving it so youre ignoring it
}
}else{
Char c = getNextChar();
//now you can add this character to your output string

for example. You can use ignore(inputSize, "#") or you can use getline
http://www.cplusplus.com/reference/istream/istream/ignore/
http://www.cplusplus.com/reference/istream/istream/getline/

Related

Why doesn't this code correctly read strings until encountering a newline?

I'm trying to write a program that reads a bunch of strings from the user, then a newline, and pushes all the strings I've read onto a stack. Here's what I have so far:
stack<string> st;
string str;
while(str != "\n")
{
cin >> str;
st.push(str);
}
However, this goes into an infinite loop and doesn't stop when I read a newline. Why is this happening? How do I fix it?
By default, the stream extraction operator (the >> operator) as applied to strings will skip over all whitespace. If you type in A B C, then a newline, then D E F, then try reading strings one at a time using the stream extraction operator, you'll get the strings "A", "B", "C", "D", "E", and "F" with no whitespace and no newlines.
If you want to read a bunch of strings until you hit a newline, you can consider using std::getline to read a line of text, then use an std::istringstream to tokenize it:
#include <sstream>
/* Read a full line from the user. */
std::string line;
if (!getline(std::cin, line)) {
// Handle an error
}
/* Tokenize it. */
std::istringstream tokenizer(line);
for (std::string token; tokenizer >> token; ) {
// Do something with the string token
}
As a note - in your original code, you have a loop that generally looks like this:
string toRead;
while (allIsGoodFor(toRead)) {
cin >> toRead;
// do something with toRead;
}
This approach, in general, doesn't work because it will continue through the loop one time too many. Specifically, once you read an input that causes the condition to be false, the loop will keep processing what you've read so far. It's probably a better idea to do something like this:
while (cin >> toRead && allIsGoodFor(toRead)) {
do something with toRead;
}
Try doing
stack<string> st;
string str;
while(str!="\n")
{
cin>>str;
if(str == "\n")
{
break;
}
st.push(str);
}
And see if that works.
And if not, then try
while ((str = cin.get()) != '\n')
instead of
while(str!="\n")

comma separated stream into struct

I have a structure with an int and two strings. When reading in the file it is comma seperated for the first two values and the last value is terminated by a newline. The third argument could be empty however.
ex data: 7, john doe, 123-456-7891 123 fake st.
I want to make it so that my program will grab the first number and put it in the int, find the comma and put the second number in the struct's string etc.
First question is should I use a class instead? I have seen the getline(stream, myString, ','); but my arguments are different data types so I can't just throw them all into a vector.
my code:
struct Person{
int id;//dont care if this is unique
string name;
string extraInfo;
};
int main(int argc, char* argv[]){
assert( argc ==2 && "Invalid number of command line arguments");
ifstream inputFile (argv[1]);
assert( inputFile.is_open() && "Unable to open file");
}
What is the best way of storing this information and retrieving it from a file that is comma separated for the first two and ends with a newline? I also want the program to ignore blank lines in the file.
I'd read the file line-by-line using normal getline(). Then, put it into a stringstream for further parsing or use string's find() functions to split the text manually.
Some more notes:
I don't understand your first question about using a class. If you mean for Person, then the answer is that it doesn't matter.
Using assert for something you don't have control over is wrong, like argc. This should only be used to verify that you didn't make a programming error. Also, if you #define NDEBUG, the asserts are all gone, so they shouldn't really be part of your program logic. Throw std::runtime_error("failed to open file") instead.
You probably don't want the double quotes in your strings. Also, you might want "a,b" to not be split by the comma. Make sure you have tests that assert the required functionality.
You can still use the getline approach for tokenising a line, but you first have to read the line:
vector<Person> people;
string line;
int lineNum = 0;
while( getline(inputFile, line) )
{
istringstream iss(line);
lineNum++;
// Try to extract person data from the line. If successful, ok will be true.
Person p;
bool ok = false;
do {
string val;
if( !getline(iss, val, ',') ) break;
p.id = strtol( val.c_str(), NULL, 10 );
if( !getline(iss, p.name, ',') ) break;
if( !getline(iss, p.extraInfo, ',') ) break;
// Now you can trim the name and extraInfo strings to remove spaces and quotes
//[todo]
ok = true;
} while(false);
// If all is well, add the person to our people-vector.
if( ok ) {
people.push_back(p);
} else {
cout << "Failed to parse line " << lineNum << ": " << line << endl;
}
}
Once you get the line in string using getline, use strtok.
char myline[] = "7, john doe, 123-456-7891 123 fake st.";
char tokens = strtok(myline, ",");
while(tokens)
{
//store tokens in your struct values here
}
You'll need to include #include <string.h> to use strtok

Parsing File I/O

I writing a C++ program that needs to be able to read from a .txt file, and parse the input in order to be able to get commands and arguments from each line.
Say I have Animals.txt
A cat1 3
A dog1 4
A cat2 1
D cat1
I want to be able to take this file, and then create a set of if statements for the first letter, so that I can call a function in the main class that corresponds to the first letter, and pass the rest of the line in as arguments.
An exmaple of what i'm trying to do:
if(line[0].compare("A")==0){
add(line[1],line[2]);
}
if(line[0].compare("D")==0){
delete(line[1])
}
I've tried to use strtok and the stringstream classes, but either I dont know how to implement the for my needs or they do not work for my needs as values are being put in line[0] that are not at the beginning of the lines of the text file.
Any help would be much appreciated.
First you need std::ifstream to open the file. Then you need std::getline to extract lines from the file:
std::ifstream file("Animals.txt");
std::string line;
while (std::getline(file, line)) {
// ...
}
Then inside the while loop, stick the line in a std::stringstream and extract the values you need:
std::stringstream ss(line);
char letter;
ss >> letter;
// And so on...
For a char you can do simple == comparison in your if statements:
if (letter == 'A') {
// ...
}
If you extract the letter into a std::string, just make sure you compare against "A".
I'll let you plug it all together and figure out the rest.
Create a istringstream object to split each line:
std::istringstream line(my_line);
std::string line0;
std::string line1;
std::string line2;
line >> token;
if (line0 == "A") {
line >> line1 >> line2;
add(line1, line2);
} else if (line0 == "D") {
line >> line1;
remove(line1);
}

Modify cin to also return the newlines

I know about getline() but it would be nice if cin could return \n when encountered.
Any way for achieving this (or similar)?
edit (example):
string s;
while(cin>>s){
if(s == "\n")
cout<<"newline! ";
else
cout<<s<<" ";
}
input file txt:
hola, em dic pere
caram, jo també .
the end result shoud be like:
hola, em dic pere newline! caram, jo també .
If you are reading individual lines, you know that there is a newline after each read line. Well, except for the last line in the file which doesn't have to be delimited by a newline character for the read to be successful but you can detect if there is newline by checking eof(): if std::getline() was successful but eof() is set, the last line didn't contain a newline. Obviously, this requires the use of the std::string version of std::getline():
for (std::string line; std::getline(in, line); )
{
std::cout << line << (in.eof()? "": "\n");
}
This should write the stream to std::cout as it was read.
The question asked for the data to be output but with newlines converted to say "newline!". You can achieve this with:
for (std::string line; std::getline(in, line); )
{
std::cout << line << (in.eof()? "": "newline! ");
}
If you don't care about the stream being split into line but actually just want to get the entire file (including all newlines), you can just read the stream into a std::string:
std::string file((std::istreambuf_iterator<char>(in)),
std::istreambuf_iterator<char>());
Note, however, that this exact approach is probably fairly slow (although I know that it can be made fast). If you know that the file doesn't contain a certain character, you can also use std::getline() to read the entire file into a std::string:
std::getline(in, file, 0);
The above code assumes that your file doesn't contain any null characters.
A modification of #Dietmar's answer should do the trick:
for (std::string line; std::getline(in, line); )
{
std::istringstream iss(line);
for (std::string word; iss >> word; ) { std::cout << word << " "; }
if (in.eof()) { std::cout << "newline! "; }
}
Just for the record, I ended up using this (I wanted to post it 11h ago)
string s0, s1;
while(getline(cin,s0)){
istringstream is(s0);
while(is>>s1){
cout<<s1<<" ";
}
cout<<"newline! ";
}

What am I missing? GetLine function (C++)

string GetLine()
{
char parameter[26] = {NULL};
inFile.getline (parameter,26,' ');
return parameter;
}
Now an example of my input file looks like this:
~in.txt~
BAC BCA(space after the last A)
~End File~
I have to have that space after the A or else my function to get line won't work. Is there a way to not have a space after the A and still get it to work?
I have 26, because the input line will only have up to 26 letters in it.
I need to have them separated like I have it because this is how I use it:
string in, post;
in = GetLine();
post = GetLine();
Thanks for any suggestions on this, this is very small chunk of code for the program i'm still working on. I just wanna cover my bases because my Professor is testing this program with his own input file and I don't know if his input file will end with a space.
This is kind of a silly redundant function, and I don't know why you would call it "GetLine", but here ya go:
string GetLine()
{
string s;
infile >> s;
return s;
}
Perhaps you should just get the line allowing \n to be the delimiter and then just iterate through and tokenize the input by spaces.
Something like this is a much smarter way to do this:
ifstream file(filename);
string line;
if (file)
{
string token;
stringstream iss;
while ( getline(file, line) )
{
iss << line;
while ( getline(iss, token, ' ') )
{
cout << token << endl;
}
iss.clear();
}
}
The EOF and getline don't get along terribly well, so I found this online a few semesters ago when working on a simple parsing problem.
If you know that in and post will have the same length, then here is a solution:
Give GetLine() a char parameter, say delim, that determines the delimiter character.
string GetLine(char delim=' ')
And have it used in the getline call:
inFile.getline (parameter,26,delim);
Then read the lines like this:
string in, post;
in = GetLine(' ');
post = GetLine('\n');
EDIT:
If you don't know whether their will be a space at the end or not, use this:
string GetLine()
{
char parameter[26] = {NULL};
inFile.getline (parameter,26,' ');
string str = parameter;
if (str[str.length()-1]==' ') str.resize(str.length()-1);
return str;
}