Extract data from c++ string - c++

I wanted to extract the values from the string in C++. I guess this is not the C++ way of doing this, but that one in particular doesn't work. Any ideas?
string line = "{10}{20}Hello World!";
int start;
int end;
string text;
// What to use here? Is the sscanf() a good idea? How to implement it?
cout << start; // 10
cout << end; // 20
cout << text; // Hello World!

Although you can make sscanf work, this solution is more appropriate for C programs. In C++ you should prefer string stream:
string s("{10}{20}Hello World!");
stringstream iss(s);
Now you can use the familiar stream operations for reading input into integers and strings:
string a;
int x, y;
iss.ignore(1, '{');
iss >> x;
iss.ignore(1, '}');
iss.ignore(1, '{');
iss >> y;
iss.ignore(1, '}');
getline(iss, a);
Demo.

You could use the method String.find() to get the positions of '{' and '}' and then extract the data you want through String.substr().

text does not need to have an "&" in front of it inside the sscanf, since string names are already pointers to their starting address.
sscanf(line, "{%d}{%d}%s", &start, &end, text);

Related

Stringstream Delimiter

Is there a default delimiter for stringstream? From my research, I understood that I can use it to split a string using space and comma as delimiters. But can I use other delimiters for stringstream?
Here is a C++ code snippet :
vector<int> parseInts(string str) {
// Complete this function
stringstream ss(str);
vector<int> res;
char ch;
int x;
while(ss){
ss >> x >> ch;
res.push_back(x);
}
return res;
}
This code works without me mentioning any specific delimiter. How does that happen?
There is no "delimiter" for streams at all. operator>>, on the other hand, implements its reading by delimiting on whitespace characters. For other delimiter characters, you can use std::getline() instead, eg:
vector<int> parseInts(string str) {
// Complete this function
istringstream iss(str);
vector<int> res;
int x;
string temp;
char delim = '-'; // whatever you want
while (getline(iss, temp, delim)) {
if (istringstream(temp) >> x) { // or std::stoi(), std::strtol(), etc
res.push_back(x);
}
}
return res;
}
This code works without me mentioning any specific delimiter. How does that happen?
streams don't know anything about delimiters. What is happening is that, on each loop iteration, you are calling ss >> x to read the next available non-whitespace substring and convert it to an integer, and then you are calling ss >> ch to read the next available non-whitespace character following that integer. The code doesn't care what that character actually is, as long as it is not whitespace. Your loop runs until it reaches the end of the stream, or encounters a reading/conversion error.

How can I split a getline() into array in c++

I have an input getline:
man,meal,moon;fat,food,feel;cat,coat,cook;love,leg,lunch
And I want to split this into an array when it sees a ;, it can store all values before the ; in an array.
For example:
array[0]=man,meal,moon
array[1]=fat,food,feel
And so on...
How can I do it? I tried many times but I failed!😒
Can anyone help?
Thanks in advance.
You can use std::stringstream and std::getline.
I also suggest that you use std::vector as it's resizeable.
In the example below, we get input line and store it into a std::string, then we create a std::stringstream to hold that data. And you can use std::getline with ; as delimiter to store the string data between the semicolon into the variable word as seen below, each "word" which is pushed back into a vector:
int main()
{
string line;
string word;
getline(cin, line);
stringstream ss(line);
vector<string> vec;
while (getline(ss, word, ';')) {
vec.emplace_back(word);
}
for (auto i : vec) // Use regular for loop if you can't use c++11/14
cout << i << '\n';
Alternatively, if you can't use std::vector:
string arr[256];
int count = 0;
while (getline(ss, word, ';') && count < 256) {
arr[count++] = word;
}
Live demo
Outputs:
man,meal,moon
fat,food,feel
cat,coat,cook
love,leg,lunch
I don't want to give you some code because you must be new at C++ and you have to learn by yourself but I can give an hint: use substring to store it into a vector of string.

c++ parsing lines in file as streams

I want to parse a file which describes a set of data line by line. Each datum consists of 3 or four parameters: int int float (optional) string.
I opened file as ifstream inFile and used it in a while loop
while (inFile) {
string line;
getline(inFile,line);
istringstream iss(line);
char strInput[256];
iss >> strInput;
int i = atoi(strInput);
iss >> strInput;
int j = atoi(strInput);
iss >> strInput;
float k = atoi(strInput);
iss >> strInput;
cout << i << j << k << strInput << endl;*/
}
The problem is that the last parameter is optional, so I'll probably run into errors when it is not present. How can i check in advance how many parameters are given for each datum?
Furthermore,
string line;
getline(inFile,line);
istringstream iss(line);
seems a bit reduldant, how could I simplyfiy it?
Use the idiomatic approach in this situation, and it becomes much simpler:
for (std::string line; getline(inFile, line); ) {
std::istringstream iss(line);
int i;
int j;
float k;
if (!(iss >> i >> j)) {
//Failed to extract the required elements
//This is an error
}
if (!(iss >> k)) {
//Failed to extract the optional element
//This is not an error -- you just don't have a third parameter
}
}
By the way, atoi has some highly undesired ambiguity unless 0 is not a possible value for the string you're parsing. Since atoi returns 0 when it errors, you cannot know if a return value of 0 is a successful parsing of a string with a value of 0, or if it's an error unless you do some rather laborious checking on the original string you had it parse.
Try to stick with streams, but in situations where you do need to fall back to atoi type functionality, go with the strtoX family of functions (strtoi, strtol, strtof, etc). Or, better yet, if you're using C++11, use the stoX family of functions.
You could use a string tokenizer How do I tokenize a string in C++?
In particular: https://stackoverflow.com/a/55680/2436175
Side note: you do not need to use atoi, you could simply do:
int i,j;
iss >> i >> j;
(but this wouldn't handle alone the problem of optional elements)

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;
}

boost lexical_cast throws exception

I'm using boost libs for c++ and the function lexical_cast behaves really weird. If I do lexical_cast("0.07513994") it works fine, but if I use my variable which I need to convert, it throws the bad_lexical_cast exception. Here is the code:
string word;
istringstream iss(line);
do
{
string word;
iss >> word;
double x;
x = lexical_cast<double>(word);
cout << x << endl;
} while (iss);
What am I doing wrong here? I appreciate any help, thanks
Your problem is probably that the loop is processed one more time than you expect.
The last time through the loop, the read to word fails, setting the fail bit in iss, which is what while(iss) is checking. To fix it you need to do something like this.
string word;
istringstream iss(line);
do
{
string word;
iss >> word;
if(iss)
{
double x;
x = lexical_cast<double>(word);
cout << x << endl;
}
} while (iss);
Unlike functions such as atof() which stop parsing as soon as they see an invalid character, lexical_cast requires that every character in the input string be valid. i.e. any leading or trailing spaces will cause it to throw an exception.
You want to see what kind of input it is getting and trim it accordingly. You should also catch bad_lexical_cast just in case it does get input which is completely garbage.
One possible solution is to use boos.regex or boost.xpressive to extract a valid sub-string and pass the result to lexical_cast.
The problem is probably that you are sending an empty string when there is no data left.
You should change the loop you are using.
Use the while {} loop (not the 'do while' loop). This allows you to read from the stream and test it in a single easy to read statement. Note the result of iss >> word is the stream. When used in this boolean context it is tested to see if the state is good and its value converted into something that can be used by the while condition. Thus if the operator >> filed to work correctly then the loop is never entered.
istringstream iss(line);
string word;
while(iss >> word)
{
double x = lexical_cast<double>(word);
cout << x << endl;
}
But really you don't even need the lexical cast in this situation (unless you want to test for non numbers with an exception). The standard stream operator will convert the input into a double.
istringstream iss(line);
double word;
while(iss >> word)
{
cout << word << endl;
}
if (iss.fail())
{ /* Failure to convert input to a double */
}