Extract arbitrary data values from a std::string C++ - c++

I have strings like this
10z45
9999i4a
Basically int-char-int-optionalchar
I want to do this function prototype
void process(std::string input, int &first, char &c, int &last, bool &optional)
Only thing is I'm not sure the best way to iterate over the string to extract these values. Would rather not use regex library, seems like can be done simply?

Use a string stream:
#include <sstream>
...
std::istringstream iss(input);
iss >> first >> c >> last >> optional;
If there's no final character, the value of optional won't be touched, so I'd recommend setting it to 0 beforehand.

Use std::istringstream, read int, char, int, then try next char:
std::istringstream is(input);
is >> first >> c >> last;
char c2;
optional = (is >> c2);
I'm not sure this is 100% what you want -but I'd do it in this way.

Related

C++ String stream ignore() not working

I was solving a question on hackerrank and came across this problem involving string streams.
https://www.hackerrank.com/challenges/c-tutorial-stringstream/problem
For Extracting data, hackerrank has given an example:
stringstream ss("23,4,56");
char ch;
int a, b, c;
ss >> a >> ch >> b >> ch >> c; // a = 23, b = 4, c = 56
However, when I try to export it to a vector, I have to escape the ',' using:
stringstream ss(str);
vector<int> vect;
int i;
while (ss >> i)
{
vect.push_back(i);
if (ss.peek() == ',')
ss.ignore();
}
Why can't I use the extraction operation to get the required word here? Shouldn't the stream escape the ','(Sorry for the noob-level question)?
operator>> extracts the next delimited token, only so far as characters actually belong to the requested data type. So, when using operator>> to read an int, it will extract only digits, not letters, punctuation, etc. That means a comma following a number has to be read separately.
In the first example:
ss >> a reads the first int in the stream
then >> ch reads the comma after it
then >> b reads the next int
then >> ch reads the comma after it
then >> c reads the next int
In the second example:
ss >> i reads the next int in the stream, breaking the loop if fails or EOF
then ss.peek() checks if a comma exists (since the last int doesn't have one), and if found then ss.ignore() skips past it
goto #1
If you try to use operator>> to read a comma that doesn't exist, it will set the stream's eofbit state and fail the extraction. If you use while (ss >> i >> ch), the while would evaluate as false when the last int is reached. Even though ss >> i would succeed, >> ch would fail, and thus i would not be added to the vector.
In theory, you could replace if (ss.peek() == ',') ss.ignore(); inside the loop with char ch; ss >> ch instead. The end effect would be the same, at least for a string like "23,4,56". But, let's say you were given something like "23 4 56" instead. The first example would fail to handle that correctly, but the second example would handle it just fine when using peek()+ignore(), but not when using ss >> ch.
I think you can use this code to escape the ','
std::string valstr;
while (std::getline(ss, valstr, ','))
{
vect.push_back(std::stoi(valstr));
}

Count of a data type in a file in C++

I have a file with strings and integers. For example, this is how my file is
string int int string int int
How do I get the count of only strings in the file? I thought of writing the count in the beginning of the file. But the count was not proper while reading.
If it is a text file, you can easily read the "words" from the file and then determine if they are numbers or not using atoi, atol, atoll, atoq. And when you got an answer (ie: this is a number, or not), just increment a variable :)
Parse through each item. For each item compare the ascii values of the characters in it.If it is between 48 and 57(inclusive) , it is an int. Otherwise it is a string.
std::string word;
while (std::cin >> word)
{
std::istringstream iss(word);
int my_int;
char garbage;
num_ints += (iss >> my_int) && !(iss >> garbage);
++num_words;
}
num_strings = num_words - num_ints;

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)

C++: Reading from stringstream

I have an istringstream object with string of format
STRING,INT,INT,INT
eg.
"name,20,30,40"
I want to read the values into variables of specific types such as std:string and int.
How can I do that?
The lazy way:
getline(stream, str, ',');
char c;
stream >> i1 >> c >> i2 >> c >> i3;
It is "lazy" because it does not handle format errors in any sensible way.
The smarter ways would be split on commas into a vector of strings (which can then be converted into integers as needed), or use a full-fledged parser, such as boost.spirit.

c++, get phone number from txt file

I'm trying input a phone number in the format: 555-555-5555 into a struct with three int's. I've tried using getline with a delimiter of "-", but I keep getting the error: "cannot convert parameter 1 from 'int' to 'char *'".
I tried creating a temp char* variable to store the number in and then type casting it to int, but that didn't work.
How should I go about doing this?
Thanks
edit:
here's some of the code:
void User::Input(istream& infile) {
char* phone_temp;
...
infile.getline(phone_temp, sizeof(phoneNum.areaCode), "-");
phoneNum.areaCode = (int)phone_temp;
...
}
Since you are posting this as a c++ question, and not a c question, Use istringstream
http://www.cplusplus.com/reference/iostream/istringstream/
From my head it your code would become something like:
std::string sPhoneNum("555-555-5555");
struct
{
int p1;
int p2;
int p3;
} phone;
char dummy;
std::istringstream iss(sPhoneNum);
iss >> phone.p1; // first part
iss >> dummy; // '-' character
iss >> phone.p2; // second part
iss >> dummy; // '-' character
iss >> phone.p2; // last part
EDIT:
now that you have posted example code, I see you already start with an istream, you can just use the >> operator directly, no need to create another istringstream operator. See examples: http://www.cplusplus.com/reference/iostream/istream/operator%3E%3E/
Also, stay away from c-style conversion methods with char * and atoi stuff if you don't have to, working with std::string and istreams is the "right" C++ way. It avoids memory leaks and other nasty problems.
Reading a phone number from a stream:
Assuming the number is well formatted:
void User::Input(istream& infile)
{
int part1;
int part2;
int part3;
char dash1;
char dash2;
infile >> part1 >> dash1 >> part2 >> dash2 >> part3;
/*
* !infile will return false if the file is in a bad state.
* This will happen if it fails to read a number from
* the input stream or the stream ran out of data.
*
* Both these conditions constitute an error as not all the values will
* be set correctly. Also check that the dash[12] hold the dash character.
* Otherwise there may be some other formatting problem.
*/
if ((!infile) || (dash1 != '-') || (dash2 != '-'))
{
throw int(5); // convert this to your own exception object.
}
}
if I understand correctly, try atoi() or stringstream to convert from char* to int
See this example on how you can tokenize the line. This question will also help.
Then use atoi to convert string to int.
You can't cast a char* to an int and expect a correct value. A char* is an address in memory, so when you cast it to int, you'll get a memory address in your int. You need to call a function, such as atoi() to algorithmically convert the data char* is pointing to into an integer.
Another viable option, although not quite C++, is:
char a[10],b[10],c[10];
scanf("%d-%d-%d", a, b, c);
It appears you're trying to convert a char to an integer, in which case you'd want to use the atoi function or a string stream.
rather than using infile.getline() use the free standing version with a std::string:
getfile(infile, buffer);
After that, if you'd like you can do an addition getline():
istringstream phonenumber(buiffer);
string areacode = getline(phonenumber, part1. '-');
or you can use the extractor >> (that's what it's for!)
int areacode;
phonenumber >> areacode;
Just a side note: if you're using char* do make sure you allocate space for it, or at least point to allocated space.