When I read a string with getline method in C++ it's adding a space in front of my string.
What should I do to eliminate that?
This is my code:
void read_from_file(_Longlong mobile_number) {
string number = to_string(mobile_number);
fstream read(number + "messages_not_seen.txt", ios::in);
_Longlong mobile_numer;
string first_name;
string last_name;
char txt[500];
int Priority;
while (read) {
read >> first_name >> last_name >> mobile_numer;
read.getline(txt, 500);
if (read.eof()) {
break;
}
push(mobile_numer, first_name, last_name, txt);
}
}
The >> operator leaves delimiting whitespace in the stream. Usually, it's not a problem because the >> operator will also ignore leading whitespace, but if you use getline() after the extraction, the space will get included into the string.
You can ignore leading spaces with something like
while (std::isspace(static_cast<unsigned char>(std::cin.peek()))) std::cin.ignore();
Or just call cin.ignore() once if you're sure there is exactly one leading space.
Something you might find helpful is the non-member std::getline() function, which works with std::string instead of character arrays.
If you're using modern C++ (C++-11 and up), you can use lambdas in order to do so.
#include <algorithm>
#include <cctype>
#include <locale>
#include <iostream>
using namespace std; // not recommended, but I assume you're a beginner.
// trim from start (in place)
static inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
return !std::isspace(ch);
}));
}
void read_from_file(_Longlong mobile_number)
{
string number = to_string(mobile_number);
fstream read(number + "messages_not_seen.txt", ios::in);
_Longlong mobile_numer;
string first_name;
string last_name;
// char txt[500]; // why are you using C-style char here?
string txt; // use string instead
int Priority;
while (read)
{
read >> first_name >> last_name >> mobile_number;
ltrim(read.get(cin, txt));
if (read.eof())
{
break;
}
push(mobile_numer, first_name, last_name, txt);
}
}
And don't forget the main function where you invoke all of these.
Related
I have a function that prompts the user for input. If they input more than the number of words I want(3), then an error should be printed. How do I approach this? I found out how to check if the input is < 3, but not > 3.
struct Info
{
std::string cmd;
std::string name;
std::string location;
}
Info* get_string()
{
std::string raw_input;
std::getline(std::cin, raw_input);
std::istringstream input(raw_input);
std::string cmd;
std::string name;
std::string location;
input>>cmd;
input>>name;
input>>location;
Info* inputs = new Info{cmd, name, location};
return inputs;
}
The function I have automatically takes 3 strings and stores them in my struct, which I check later to see if any part of the struct is empty (for example: "Run" "Joe" ""), but what if they enter in 4 strings? Thank you
you can split the input string into words with a space delimiter and then check the number of words. you can use the function below to split your input. after this you can check the size of the vector.
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
using namespace std;
vector<std::string> split(const string &s, char delim) {
stringstream ss(s);
string item;
vector<string> res;
while (getline(ss, item, delim)) {
if(item.length()==0)continue;
res.push_back(item);
}
return res;
}
int _tmain(int argc, _TCHAR* argv[])
{
string theString;
cin>>theString;
vector<string> res=split(theString, ' ');
if(res.size()>3)
{
//show error
}
return 0;
}
The problem with this and with Ferdinand's idea is that in order to test if a 4th string exists, you have to "ask" for it. If it exists, you can error, but if it doesn't then it sits there waiting for input and the user wonders what is going wrong.
Thus I'm going to modify your code slightly. It's fairly straight forward. If the user enters a space in the last "word", then you know that there is an issue and can deal with it as you wish.
// Replace input >> location; with the below
// Get until the line break, including spaces
getline(input, location);
// Check if there is a space (I.e. 2+ words)
if(location.find(" ") != string::npos){
// If so, fail
}
Resources for learning:
http://www.cplusplus.com/reference/string/string/find/
http://www.cplusplus.com/reference/string/string/getline/
I am relatively new to C++, so be gentle.
I have a text-file I want to read, but when i read the file it skips the whitespace (space) between separated words.
I tried to take away as much junk-code as possible so it would be easier to read.
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;
int main(.....)
{
ifstream in_file;
string filename;
string status;
readStringToMem(in_file, status);
cout << "Type in the filename : ";
getline(cin, filename);
in_file.open(filename);
readStringToMem(in_file, status);
}
void readStringToMem(ifstream& in_file, string& string_value)
{
string input_string;
getline(in_file, input_string, '|');
stringstream myInputStream(input_string);
myInputStream >> string_value;
}
My file may look like this:
Status is ok | 100
But when I read it, it comes out like this:
Status 100
Thanks in advance! Any help will be great!
You are trying too hard, this
void readStringToMem(ifstream& in_file, string& string_value)
{
string input_string;
getline(in_file, input_string, '|');
stringstream myInputStream(input_string);
myInputStream >> string_value;
}
should be this
void readStringToMem(ifstream& in_file, string& string_value)
{
getline(in_file, string_value, '|');
}
Much simpler, in fact readStringToMem is so simple I wonder if it's worth putting into a separate function.
I think you were probably confused by the integer case. In that case you have to convert the string you have read with getline to an integer. And you would do that using stringstream. But in the string case you already have a string so there is no conversion to do and no need for stringstream.
Hey all so I have to get values from a text file, but the values don't stand alone they are all written as this:
Population size: 30
Is there any way in c++ that I can read from after the ':'?
I've tried using the >> operator like:
string pop;
inFile >> pop;
but off course the whitespace terminates the statement before it gets to the number and for some reason using
inFile.getline(pop, 20);
gives me loads of errors because it does not want to write directly to string for some reason..
I don't really want to use a char array because then it won't be as easy to test for the number and extract that alone from the string.
So is there anyway I can use the getline function with a string?
And is it possible to read from after the ':' character?
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <cstdlib>
using namespace std;
int main()
{
string fname;
cin >> fname;
ifstream inFile;
inFile.open(fname.c_str());
string pop1;
getline(inFile,pop1);
cout << pop1;
return 0;
}
ok so here is my code with the new getline, but it still outputs nothing. it does correctly open the text file and it works with a char array
You are probably best to read the whole line then manipulate the string :-
std::string line;
std::getline(inFile, line);
line = line.substr(19); // Get character 20 onwards...
You are probably better too looking for the colon :-
size_t pos = line.find(":");
if (pos != string::npos)
{
line = line.substr(pos + 1);
}
Or something similar
Once you've done that you might want to feed it back into a stringstream so you can read ints and stuff?
int population;
std::istringstream ss(line);
ss >> population;
Obviously this all depends on what you want to do with the data
Assuming your data is in the form
<Key>:<Value>
One per line. Then I would do this:
std::string line;
while(std::getline(inFile, line))
{
std::stringstream linestream(line);
std::string key;
int value;
if (std::getline(linestream, key, ':') >> value)
{
// Got a key/value pair
}
}
As an exercise, I'm trying to create a input stream manipulator that will suck up characters and put them in a string until it encounters a specific character or until it reaches eof. The idea came from Bruce Eckel's 'Thinking in c++' page 249.
Here's the code I have so far:
#include <string>
#include <iostream>
#include <istream>
#include <sstream>
#include <fstream>
#include <iomanip>
using namespace std;
class siu
{
char T;
string *S;
public:
siu (string *s, char t)
{
T = t;
S = s;
*S = "";
}
friend istream& operator>>(istream& is, siu& SIU)
{
char N;
bool done=false;
while (!done)
{
is >> N;
if ((N == SIU.T) || is.eof())
done = true;
else
SIU.S->append(&N);
}
return is;
}
};
and to test it....
{
istringstream iss("1 2 now is the time for all/");
int a,b;
string stuff, zork;
iss >> a >> b >> siu(&stuff,'/');
zork = stuff;
}
the idea being that siu(&stuff,'/') will suck up characters from iss until it encounters the /. I can watch it with the debugger as it gets the characters 'n' 'o' 'w' through '/'
and terminates the loop. It all seems to be going swimingly until I look at Stuff. Stuff has the characters now etc BUT there are 6 extra characters between each of them. Here's a sample:
&stuff 0x0012fba4 {0x008c1861 "nÌÌÌýoÌÌÌýwÌÌÌýiÌÌÌýsÌÌÌýtÌÌÌýhÌÌÌýeÌÌÌýtÌÌÌýiÌÌÌýmÌÌÌýeÌÌÌýfÌÌÌýoÌÌÌýrÌÌÌýaÌÌÌýlÌÌÌýlÌÌÌý"}
What's going on?
This line:
SIU.S->append(&N);
appends the character as a char *. The append function is expecting a null terminated string, so it keeps reading from &N, (&N)+1... until it sees a zero byte.
You can either make up a small null terminated char array and pass that in, or you can use the an alternate append function that takes a count and a character to append:
SIU.S->append(1, N);
I have data in the following format:
4:How do you do?
10:Happy birthday
1:Purple monkey dishwasher
200:The Ancestral Territorial Imperatives of the Trumpeter Swan
The number can be anywhere from 1 to 999, and the string is at most 255 characters long. I'm new to C++ and it seems a few sources recommend extracting formatted data with a stream's >> operator, but when I want to extract a string it stops at the first whitespace character. Is there a way to configure a stream to stop parsing a string only at a newline or end-of-file? I saw that there was a getline method to extract an entire line, but then I still have to split it up manually [with find_first_of], don't I?
Is there an easy way to parse data in this format using only STL?
The C++ String Toolkit Library (StrTk) has the following solution to your problem:
#include <string>
#include <deque>
#include "strtk.hpp"
int main()
{
struct line_type
{
unsigned int id;
std::string str;
};
std::deque<line_type> line_list;
const std::string file_name = "data.txt";
strtk::for_each_line(file_name,
[&line_list](const std::string& line)
{
line_type temp_line;
const bool result = strtk::parse(line,
":",
temp_line.id,
temp_line.str);
if (!result) return;
line_list.push_back(temp_line);
});
return 0;
}
More examples can be found Here
You can read the number before you use std::getline, which reads from a stream and stores into a std::string object. Something like this:
int num;
string str;
while(cin>>num){
getline(cin,str);
}
You've already been told about std::getline, but they didn't mention one detail that you'll probably find useful: when you call getline, you can also pass a parameter telling it what character to treat as the end of input. To read your number, you can use:
std::string number;
std::string name;
std::getline(infile, number, ':');
std::getline(infile, name);
This will put the data up to the ':' into number, discard the ':', and read the rest of the line into name.
If you want to use >> to read the data, you can do that too, but it's a bit more difficult, and delves into an area of the standard library that most people never touch. A stream has an associated locale that's used for things like formatting numbers and (importantly) determining what constitutes "white space". You can define your own locale to define the ":" as white space, and the space (" ") as not white space. Tell the stream to use that locale, and it'll let you read your data directly.
#include <locale>
#include <vector>
struct colonsep: std::ctype<char> {
colonsep(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::mask());
rc[':'] = std::ctype_base::space;
rc['\n'] = std::ctype_base::space;
return &rc[0];
}
};
Now to use it, we "imbue" the stream with a locale:
#include <fstream>
#include <iterator>
#include <algorithm>
#include <iostream>
typedef std::pair<int, std::string> data;
namespace std {
std::istream &operator>>(std::istream &is, data &d) {
return is >> d.first >> d.second;
}
std::ostream &operator<<(std::ostream &os, data const &d) {
return os << d.first << ":" << d.second;
}
}
int main() {
std::ifstream infile("testfile.txt");
infile.imbue(std::locale(std::locale(), new colonsep));
std::vector<data> d;
std::copy(std::istream_iterator<data>(infile),
std::istream_iterator<data>(),
std::back_inserter(d));
// just for fun, sort the data to show we can manipulate it:
std::sort(d.begin(), d.end());
std::copy(d.begin(), d.end(), std::ostream_iterator<data>(std::cout, "\n"));
return 0;
}
Now you know why that part of the library is so neglected. In theory, getting the standard library to do your work for you is great -- but in fact, most of the time it's easier to do this kind of job on your own instead.
Just read the data line by line (whole line) using getline and parse it.
To parse use find_first_of()
int i;
char *string = (char*)malloc(256*sizeof(char)); //since max is 255 chars, and +1 for '\0'
scanf("%d:%[^\n]s",&i, string); //use %255[^\n]s for accepting 255 chars max irrespective of input size
printf("%s\n", string);
Its C and will work in C++ too. scanf provides more control, but no error management. So use with caution :).