I have tried to convert a color code by reading a file, retrieve the color code and store it as a string. This works, but when I tried to just simply convert it to an int, it doesn't work - always getting 0 when I do a cout.
string value = "0xFFFFFF";
unsigned int colorValue = atoi(value.c_str());
cout << colorValue << endl;
as you can see, the color I've got is 0xFFFFFF, but converting it to an int will only give me 0. Can someone please tell me what I'm missing or what i'm doing wrong?
Thanks
I suggest using stringstreams:
std::string value = "0xFFFFFF";
unsigned int colorValue;
std::stringstream sstream;
sstream << std::hex << value;
sstream >> colorValue;
cout << colorValue << endl;
As #BartekBanachewicz says, atoi() is NOT the C++ way of doing this. Leverage the power of C++ streams and use std::istringstream to do it for you. See this.
An excerpt:
template <typename DataType>
DataType convertFromString(std::string MyString)
{
DataType retValue;
std::stringstream stream;
stream << std::hex << MyString; // Credit to #elusive :)
stream >> retValue;
return retValue;
}
Related
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.
I'm trying to create a replacement for sprintfs' %05d behavior. Althought, I've found a similar question here on stackoverflow, the proposed solution there doesn't work for me when I'm testing with negative numbers.
Doing a "sprintf(buf, "%05d", -12)", I'm getting "-0012" back which looks nice.
Using stringstream, width and fill, I'm getting "00-12" which seams reasonable when looking at the docs from std::basic_ios::fill
The fill character is the character used by output insertion functions to fill spaces when padding results to the field width.
but doesn't look like something one could wish.
So I'm confused and don't know if I'm doing something obvious wrong or if width/fill from the std streams doesn't easily support this situation.
A compilable testcode can be found on codepad.
Here's an extract of the stream based conversion:
std::string NumberToString(const long iVal, const int iNumDigit)
{
std::stringstream ss;
if (iNumDigit >= 0) ss.fill(' ');
else if (iNumDigit < 0) ss.fill('0');
ss.width(std::abs(iNumDigit));
ss << iVal;
return ss.str();
}
EDIT1: Solution:
To match the std stream approach with printf formatting for %05d, jrok's solution can be used for the case with leading zeros. Here's the new function:
std::string NumberToString(const long iVal, const int iNumDigit)
{
std::stringstream ss;
if (iNumDigit >= 0) ss.fill(' ');
else if (iNumDigit < 0) { ss.fill('0'); ss.setf(std::ios::internal, std::ios::adjustfield); }
ss.width(std::abs(iNumDigit));
ss << iVal;
return ss.str();
}
Use stream manipulator std::internal.
It (along with std::left and std::right) lets you specify where the fill characters go. For example
std::cout << std::setw(5) << std::setfill('0') << std::internal << -1;
will print -0001.
I would like to know why I am getting the result of 0 when converting a hex string (0x1) to a uint8.
I tried to use boost::lexical_cast but I get a bad_lexical_cast exception. Therefore, I decided to use a stringstream instead but I am getting the incorrect value.
...
uint8_t temp;
std::string address_extension = "0x1";
std::cout << "Before: " << address_extension << std::endl;
StringToNumeric(address_extension, temp);
std::cout << "After: " << temp << std::endl;
...
template <typename T>
void StringToNumeric(const std::string& source, T& target)
{
//Check if source is hex
if(IsHexNotation(source))
{
std::stringstream ss;
//Put value in the stream
ss << std::hex << source;
//Stream the hex value into a target type
ss >> target;
}
}
You can be assured that IsHexNotation() works correctly and does not change the source as it is declared:
bool IsHexNotation(const std::string& source)
What is the correct way to convert a hex string to a uint8 (given that the hex string WILL fit into the datatype)?
Using code like this works for me:
std::stringstream ss;
int target(0);
ss << std::hex << source;
if (ss >> target) {
std::cout << "value=" << target << '\n';
}
else {
std::cout << "failed to read value\n";
}
However, I remember that there was a discussion on where the read position of a string stream should be after a write. Since it mostly follows the model of file streams, you'd need to seek to desired position, even if it is the same position. Some implementations used a common position and others used separate read and write positions. You can try using
ss.seekg(0, std::ios_base::beg);
to make sure that the read position is at the start of the stream. Alternatively, and in my opinion preferable, is to initialize an std::istringstream and read from that directly:
std::istringstream in(source);
if (in >> std::hex >> target) { ... }
Note, that you always want to check if the extraction was successful: this way you get a hint that something actually went wrong and the value 0 may be just some initial value of the variable.
I am making a statistics collector that reads the log of a music player and lets the user show top ten most played etc. As a noob project.
A line from the log looks like: "20:42:03 start E:\ROTATION\A\HÃ¥kan Lidbo - Dammlunga.mp3"
I have put this in a string using ifstream and getline.
Then making an array of chars of the string using
const char *charveqtur = newline.c_str();
Then I tried to sort i out with sscanf:
sscanf (charveqtur, "%d:%d:%d\tstart\t%s", &this->hour, &this->minute, &this->second, &this->filename);
The problem is that the filename is cut at the first space. I have also tried using istringstream instead but no breakthrough so far.
Which is the most convinient way of doing this? Thanks.
You can use some input stream to read the first integers and colons, and because the filename is the last entity, you can then use std::getline. However, even if your filename is not the last part, note that std::getline is quite a versatile function that accepts any delimiter.
A more advanced method would be to define your own type for filenames and overload operator>>(std::istream &, T const &) on it.
Here is a complete example using std::getline and stringstream with basic diagnostics and some reformatting:
#include <sstream> // for istringstream
#include <iostream> // for cout and cerr
#include <iomanip> // for setprecision
#include <cmath>
bool read (std::string const &line) {
char c = 0;
double length;
double rating;
std::string title;
std::istringstream ss;
ss.str (line);
ss >> length;
if (!ss.good()) { std::cerr << "invalid length\n"; return false; }
if (ss.get()!=':') { std::cerr << "expected colon\n"; return false; }
ss >> rating;
if (!ss.good()) { std::cerr << "invalid rating\n"; return false; }
if (ss.get()!=':') { std::cerr << "expected colon\n"; return false; }
std::getline (ss, title);
double sink;
std::cout << title << " ("
<< int(length) << ':' << 60*std::modf (length,&sink)
<< " min), your rating: " << rating << '\n';
return true;
}
int main () {
read ("30.25:5:Vivaldi - The four seasons.ogg");
read ("3.5:5:Cannibal Corpse - Evisceration Plague.ogg");
read ("meh");
return 0;
}
Output:
Vivaldi - The four seasons.ogg (30:15 min), your rating: 5
Cannibal Corpse - Evisceration Plague.ogg (3:30 min), your rating: 5
invalid length
Important: When parsing, you are sailing close to the security risks. Always be conscious and sensible and try to use tested and proven libraries where possible. This also implies that you do not use sscanf, which is not typesafe, error-prone and sometimes hard to get right.
Don't use C if you have C++, and used correctly, iostreams are even more convenient than printf/scanf+co.
You could perhaps do something like
int lastpos = 0;
if sscanf (charveqtur, "%d:%d:%d\tstart\t%n", &this->hour,
&this->minute, &this->second,
&lastpos) > 3 && lastpos >0) {
std::string filename = newline.substr(lastpos);
/* do something with filename */
}
I want to output an integer to a std::stringstream with the equivalent format of printf's %02d. Is there an easier way to achieve this than:
std::stringstream stream;
stream.setfill('0');
stream.setw(2);
stream << value;
Is it possible to stream some sort of format flags to the stringstream, something like (pseudocode):
stream << flags("%02d") << value;
You can use the standard manipulators from <iomanip> but there isn't a neat one that does both fill and width at once:
stream << std::setfill('0') << std::setw(2) << value;
It wouldn't be hard to write your own object that when inserted into the stream performed both functions:
stream << myfillandw( '0', 2 ) << value;
E.g.
struct myfillandw
{
myfillandw( char f, int w )
: fill(f), width(w) {}
char fill;
int width;
};
std::ostream& operator<<( std::ostream& o, const myfillandw& a )
{
o.fill( a.fill );
o.width( a.width );
return o;
}
You can use
stream<<setfill('0')<<setw(2)<<value;
You can't do that much better in standard C++. Alternatively, you can use Boost.Format:
stream << boost::format("%|02|")%value;
Is it possible to stream some sort of format flags to the stringstream?
Unfortunately the standard library doesn't support passing format specifiers as a string, but you can do this with the fmt library:
std::string result = fmt::format("{:02}", value); // Python syntax
or
std::string result = fmt::sprintf("%02d", value); // printf syntax
You don't even need to construct std::stringstream. The format function will return a string directly.
Disclaimer: I'm the author of the fmt library.
i think you can use c-lick programing.
you can use snprintf
like this
std::stringstream ss;
char data[3] = {0};
snprintf(data,3,"%02d",value);
ss<<data<<std::endl;