I have the following data in a c++ string
John Doe 01.01.1970
I need to extract the date and time from it into int variables. I tried it like this:
int last_space = text_string.find_last_of(' ');
int day = int(text_string.substr(last_space + 1, 2));
But I got invalid cast from type ‘std::basic_string’ to type ‘int’. When I extract the "John Doe" part in another string variable, all works fine. What's wrong?
I am trying to compile it with g++ -Wall -Werror.
You need to use
std::stringstream ss;
ss << stringVar;
ss >> intVar;
or
intVar = boost::lexical_cast<int>(stringVar);.
The later is a convenience wrapper from the boost library.
Use streams to decode integers from a string:
#include <iostream>
#include <sstream>
#include <string>
int main()
{
std::string x = "John Doe 02.01.1970";
std::string fname;
std::string lname;
int day;
int month;
int year;
char sep;
std::stringstream data(x);
data >> fname >> lname >> day >> sep >> month >> sep >> year;
std::cout << "Day(" << day << ") Month(" << month << ") Year(" << year << ")\n";
}
The operator >> when used with a string variable will read a single (white) space separate word. When used with an integer variable will read an integer from the stream (discarding any proceeding (white) space).
Try the Boost Data/Time library.
As far as I can tell, atoi does what you need.
"Parses the C string str interpreting its content as an integral number, which is returned as an int value."
http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/
Assuming (and that might be a bad assumption) that all the data was formatted similarly, I would do something like this
char name[_MAX_NAME_LENTGH], last[_MAX_NAME_LENGTH];
int month, day, year;
sscanf( text_string, "%s %s %2d.%02d.%04d", first, last, &month, &day, &year );
This does however, have the problem that the first/last names that appear in your input are only one word (i.e. this wouldn't work for things like "John M. Doe"). You would also need to define some appropriate maximum length for the string.
It's hard to be more definitive about this solution unless we know more about the input.
Related
I'm trying to figure out how to do some date validation. I need to be able to take an input from user in the form of mm/dd/yyyy and do various calculations with it to determine validity. However, I can't figure out how to split the date into three variables day,month,year after I got the input. I've played around with getline and get functions but I can't figure it out. Thanks for any help in advance from a newbie. PS I don't want to use any built in date validation functions.
int main()
{
char fill = '/';
string entered_date;
int entered_month;
int entered_year;
int entered_day;
cout << "Enter a date (mm/dd/yyyy): " << endl;
cin >> entered_date;
//getline(month, 2, '/'); < fix me
//cout << entered_month << "/" << entered_day << "/"
// << entered_year << endl;
system("Pause");
}
You can use scanf in such a case, as it provides much more functionality than cin.
int mm, dd, yyyy;
scanf("%d/%d/%d", &mm, &dd, &yyyy);
This should hopefully do the trick.
EDIT: Another way to do so would be to take the entire input in the form of a string, and then find substrings and validate each part.
string date;
cin >> date;
string delimiter = "/";
auto start = date.begin(); // iterator at beginning of string
auto finish = date.find(delimiter); // gives position of first occurrence of delimiter
if (finish == date.npos) // find returned the end of string
// delimiter does not exist in string.
else
int month = stoi(date.substr(0, finish)); // Extracts month part from date string
date = date.substr(finish+1); // Removes the month part from the date string
// Understand this piece and write further ahead.
If you know your input will be correct, then use the first part as it will be much faster. If there are chances of incorrect input, use the second as it will be more robust.
The simplest way is to use std::string::substr, and then call stoi:
#include <string>
#include <iostream>
using namespace std;
int main()
{
char fill = '/';
string entered_date;
int entered_month;
int entered_year;
int entered_day;
cout << "Enter a date (mm/dd/yyyy): " << endl;
cin >> entered_date;
entered_month = stoi(entered_date.substr(0,2));
entered_day = stoi(entered_date.substr(3,2));
entered_year = stoi(entered_date.substr(6));
}
Live example: http://ideone.com/PWyh8J
I am trying to learn C++ since yesterday and I am using this document: http://www.cplusplus.com/files/tutorial.pdf (page 32). I found a code in the document and I ran it. I tried inputting Rs 5.5 for price and an integer for quantity and the output was 0.
I tried inputting 5.5 and 6 and the output was correct.
// stringstreams
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main ()
{
string mystr;
float price = 0;
int quantity = 0;
cout << "Enter price: ";
getline (cin,mystr);
stringstream(mystr) >> price;
cout << "Enter quantity: ";
getline (cin,mystr);
stringstream(mystr) >> quantity;
cout << "Total price: " << price*quantity << endl;
return 0;
}
What exactly does the mystring command do? Quoting from the document:
"In this example, we acquire numeric values from the standard input
indirectly. Instead of extracting numeric values directly from the
standard input, we get lines from the standard input (cin) into a
string object (mystr), and then we extract the integer values from
this string into a variable of type int (quantity)."
My impression was that the function will take an integral part of a string and use that as input.
Sometimes it is very convenient to use stringstream to convert between strings and other numerical types. The usage of stringstream is similar to the usage of iostream, so it is not a burden to learn.
Stringstreams can be used to both read strings and write data into strings. It mainly functions with a string buffer, but without a real I/O channel.
The basic member functions of stringstream class are
str(), which returns the contents of its buffer in string type.
str(string), which set the contents of the buffer to the string argument.
Here is an example of how to use string streams.
ostringstream os;
os << "dec: " << 15 << " hex: " << std::hex << 15 << endl;
cout << os.str() << endl;
The result is dec: 15 hex: f.
istringstream is of more or less the same usage.
To summarize, stringstream is a convenient way to manipulate strings like an independent I/O device.
FYI, the inheritance relationships between the classes are:
From C++ Primer:
The istringstream type reads a string, ostringstream writes a string, and stringstream reads and writes the string.
I come across some cases where it is both convenient and concise to use stringstream.
case 1
It is from one of the solutions for this leetcode problem. It demonstrates a very suitable case where the use of stringstream is efficient and concise.
Suppose a and b are complex numbers expressed in string format, we want to get the result of multiplication of a and b also in string format. The code is as follows:
string a = "1+2i", b = "1+3i";
istringstream sa(a), sb(b);
ostringstream out;
int ra, ia, rb, ib;
char buff;
// only read integer values to get the real and imaginary part of
// of the original complex number
sa >> ra >> buff >> ia >> buff;
sb >> rb >> buff >> ib >> buff;
out << ra*rb-ia*ib << '+' << ra*ib+ia*rb << 'i';
// final result in string format
string result = out.str()
case 2
It is also from a leetcode problem that requires you to simplify the given path string, one of the solutions using stringstream is the most elegant that I have seen:
string simplifyPath(string path) {
string res, tmp;
vector<string> stk;
stringstream ss(path);
while(getline(ss,tmp,'/')) {
if (tmp == "" or tmp == ".") continue;
if (tmp == ".." and !stk.empty()) stk.pop_back();
else if (tmp != "..") stk.push_back(tmp);
}
for(auto str : stk) res += "/"+str;
return res.empty() ? "/" : res;
}
Without the use of stringstream, it would be difficult to write such concise code.
To answer the question. stringstream basically allows you to treat a string object like a stream, and use all stream functions and operators on it.
I saw it used mainly for the formatted output/input goodness.
One good example would be c++ implementation of converting number to stream object.
Possible example:
template <class T>
string num2str(const T& num, unsigned int prec = 12) {
string ret;
stringstream ss;
ios_base::fmtflags ff = ss.flags();
ff |= ios_base::floatfield;
ff |= ios_base::fixed;
ss.flags(ff);
ss.precision(prec);
ss << num;
ret = ss.str();
return ret;
};
Maybe it's a bit complicated but it is quite complex. You create stringstream object ss, modify its flags, put a number into it with operator<<, and extract it via str(). I guess that operator>> could be used.
Also in this example the string buffer is hidden and not used explicitly. But it would be too long of a post to write about every possible aspect and use-case.
Note: I probably stole it from someone on SO and refined, but I don't have original author noted.
You entered an alphanumeric and int, blank delimited in mystr.
You then tried to convert the first token (blank delimited) into an int.
The first token was RS which failed to convert to int, leaving a zero for myprice, and we all know what zero times anything yields.
When you only entered int values the second time, everything worked as you expected.
It was the spurious RS that caused your code to fail.
My son is learning C++ and one of his exercises it to have the user input a date in DD/MM/YYY and then output it to Month day, year
So: 19/02/2013
Output: February 19, 2013.
I am trying to help him understand the various ways but now I have confused myself.
getline()
std::string::substr()
std::string::find()
std::string::find_first_of()
std::string::find_last_of()
I can't figure it out with any of these quite right.
my current attempt to parse is:
#include <iostream>
#include <string>
using namespace std;
int main (void)
{
string date;
string line;
cout << "Enter a date in dd/mm/yyyy format: " << endl;
std::getline (std::cin,date);
while (getline(date, line))
{
string day, month, year;
istringstream liness( line );
getline( liness, day, '/' );
getline( liness, month, '/' );
getline( liness, year, '/' );
cout << "Date pieces are: " << day << " " << month << " " << year << endl;
}
}
but I am getting errors like:
`g++ 3_12.cpp -o 3_12`
`3_12.cpp: In function ‘int main()’:`
`3_12.cpp:16: error: cannot convert ‘std::string’ to ‘char**’ for argument ‘1’ to ‘ssize_t getline(char**, size_t*, FILE*)’`
`3_12.cpp:18: error: variable ‘std::istringstream liness’ has initializer but incomplete type`
int day, month, year;
char t;
std::cin >> day >> t >> month >> t >> year;
You've missed the std Regular Expressions Library! I reckon it's the safest and most effective way of doing this.
Back on topic, I think that since getline is an extern "C" function, you can't overload it using a using namespace std (which should be banned by the way). You should try prepending std to all getline calls.
For std::istringstream, you need:
#include <sstream>
P.S. Don't use using namespace std;. It's a bad habit, and it will eventually get you into trouble.
The error
3_12.cpp:16: error: cannot convert ‘std::string’ to ‘char**’ for argument ‘1’ to ‘ssize_t getline(char**, size_t*, FILE*)’
means the compiler couldn't make sense of this line:
while (getline(date, line))
Both date and line are declared as std::string and there's no overload of getline that
takes two strings. Compiler guessed that you were trying to call this function that is not part of C++ library (apparently, one of standard library headers includes stdio.h which is where that function is coming from).
The error
3_12.cpp:18: error: variable ‘std::istringstream liness’ has initializer but incomplete type
means the compiler doesn't know what std::istringstream is. You forgot to include <sstream>.
If you want to extract lines from a string by means of std::getline, you need to put it in a stringstream first, just like you do inside the loop.
Parsing dates isn't that easy. You don't want the user to be able to enter 44/33/-200 and get away with it. How I'd might approach this:
std::istringstream iss(date); // date is the line you got from the user
unsigned int day, month, year;
char c1, c2;
if (!(iss >> day >> c1 >> month >> c2 >> year)) {
// error
}
if (c1 != '/' || c2 != '/') { /* error */ }
if (month > 12) { /* error / }
// ... more of that, you get the idea
I'm trying to read a file which has input(time and price) as: 12:23:31
67 12:31:23 78 [...] I created a struct which holds values of hour,
minutes and seconds. I used strtok to tokenize the individual values
and use atof to store them. However, I'm getting an error when I try
to tokenize the time: cannot convert std::string' to 'char*' for argument 1 to 'char*'
struct time
{
int hours;
int minutes;
int seconds;
double price;
};
int main()
{
string file, input;
time* time_array;
char* tok;
cout << "Enter a file name to read input: ";
cin >> file;
ifstream file_name(file.c_str());
file_name >> input;
file_name >> input;
//while(!file_name.eof())
for(int i = 0; i < 4; i++)
{
time_array = new time;
file_name >> input;
tok = strtok(input, ":"); //ERROR HERE
while(tok != NULL)
{
*time_array.hours = atof(tok[0]);
*time_array.minutes = atof(tok[1]);
*time_array.seconds = atof(tok[2]);
}
file_name >> input;
*time_array.prine = atof(input);
}
}
I would not use strtok for this job at all1. If you want to use C-like tools, then read the data with fscanf:
// note there here `file_name` needs to be a FILE * instead of an ifstream.
fscanf(file_name, "%f:%f:%f %f", &hours, &minutes, &seconds, &price);
Most people writing C++ would prefer something more typesafe though. One possibility would be to use essentially the same format string to read the data using Boost.format.
Another possibility would be to use stream extractors:
char ignore1, ignore2;
file >> hours >> ignore1 >> minutes >> ignore2 >> seconds >> price;
As to what this does/how it works: each extractor reads one item from the input stream. the extractors for float each read a number. The extractors for char each read one character. In this case, we expect to see: 99:99:99 99, where 9 means "a digit". So, we read a number, a colon, a number, a colon, a number and another number (the extractor skips whitespace automatically). The two colons are read into char variables, and can either be ignored, or you can check that they really are colons to verify that the input data was in the correct format.
Here's a complete, compileable demo of that technique:
#include <iostream>
int main() {
float hours, minutes, seconds, price;
char ignore1, ignore2;
std::cin >> hours >> ignore1 >> minutes >> ignore2 >> seconds >> price;
std::cout << "H:" << hours
<< " M:" << minutes
<< " S:" << seconds
<< " P:" << price << "\n";
return 0;
}
There are certainly a lot more possibilities, but at least those are a few reasonable ones.
To be honest, I'm not sure there's any job for which I'd use strtok, but there are some where I might be at least a little tempted, or wish strtok weren't so badly designed so I could use it. In this case, however, I don't even see much reason to use anything similar to strtok at all.
strtok doesn't take a string as its argument - it takes a char*. Like all functions in the cstring header it's a C function that works with C strings - not C++ strings - and should generally not be used in C++.
Use the methods of the string class instead.
The short answer is that you cannot directly use a std::string with strtok, as strtok wants a string it can modify. Even if you use c_str() to get a C-style string from a std::string, it is still read only.
If you really want to use strtok, you need to duplicate the string into a modifiable buffer, for example by:
char* str = strdup(input.c_str());
If you do this, make sure you call free(str) at the end of the function, else you will get a memory leak!
Your simple case can easily be built using the string::find method. However, take a look at Boost.Tokenizer.
strtok will not work with std::string.c_str() because it returns const char*. strtok does not take a string as an argument, but rather a char*.
I want to know how can we get the string 20 from the string "TimeInterval 20".
I know that using the below code i can get the string "TimeInterval" storing at cGetMinuteInterval.
UINT iCount = strcspn("TimeInterval 20"," ");
strncpy_s(cGetMinuteInterval,MAXCHARSIZE,"TimeInterval 20",iCount);
But what if i want the string 20 from the string "TimeInterval 20" & storing at cGetMinuteInterval.
Thanks & regards,
Abhineet
As you are using C++, consider using std::string class and the substr function
Next snippet will put 20 in cGetMinuteInterval, this seems easiest in C++. What you need next is some input checks to verify that your input (format, values,...) is as expected.
std::istringstream iss("TimeInterval 20");
std::string varName;
std::string cGetMinuteInterval;
iss >> varName >> cGetMinuteInterval;
std::cout << cGetMinuteInterval << "\n";
And if you want cGetMinuteInterval as integer, just change the declaration.
Simply use this.
string str = "TimeInterval 20" ;
int position = str.find("20") ;
cout << str.substr(position) ;
I think this is what you are trying to say?