I need to convert a (decimal, if it matters) string representation of a number input from a text file to a UINT64 to pass to my data object.
size_t startpos = num.find_first_not_of(" ");
size_t endpos = num.find_last_not_of(" ");
num = num.substr(startpos, endpos-startpos+1);
UINT64 input;
//convert num to input required here
Is there any way to convert an std::string to a UINT64 in a similar way to atoi()?
Thanks!
Edit:
Working code below.
size_t startpos = num.find_first_not_of(" ");
size_t endpos = num.find_last_not_of(" ");
num = num.substr(startpos, endpos-startpos+1);
UINT64 input; //= std::strtoull(num.cstr(), NULL, 0);
std::istringstream stream (num);
stream >> input;
Use strtoull or _strtoui64().
Example:
std::string s = "1123.45";
__int64 n = std::strtoull(s.c_str(),NULL,0);
There are at least two ways to do this:
Construct a std::istringstream, and use our old friend, the >> operator.
Just convert it yourself. Parse all the digits, one at a time, converting them to a single integer. This is a very good exercise. And since this is an unsigned value, there isn't even a negative number to worry about. I would think that this would be a standard homework assignment in any introductory computer science class. At least it was, back in my days.
you can use stoull:
char s[25] = "12345678901234567890"; // or: string s = "12345678901234567890";
uint64_t a = stoull(s);
Related
console
file
Simple explanation: ifstream's get() is reading the wrong chars (console is different from file) and I need to know why.
I am recording registers into a file as a char array. When I write it to the file, it writes successfully. I open the file and find the chars I intended, except notepad apparently shows unicode character 0000 ( NULL) as a space.
For instance, the entries
id = 1000; //an 8-byte long long
name = "stack"; //variable size
surname = "overflow"; //variable size
degree = "internet"; //variable size
sex = 'c'; //1-byte char
birthdate = 256; //4-byte int
become this on the file:
& èstackoverflowinternetc
or, putting the number of unicode characters that disappear when posted here between brackets:
&[3]| [1]è|stack|overflow|internet|c| [1] | //separating each section with a | for easier reading. Some unicode characters disappear when I post them here, but I assure you they are the correct ones
SIZE| ID | name| surname| degree |g| birth
(writing is working fine and puts the expected characters)
Trouble is, when the console in the code below prints what the buffer is reading from the file, it gives me the following record (extra spaces included)
Þstackoverflowinternetc
Which is bad because it returns me the wrong ID and birthdate. Either "-21" and "4747968" or "Ù" and "-1066252288". Other fields are unnaffected. Weird because size bytes show up as empty space in the console, so it shouldn't be able to split name, surname, degree and sex.
ifstream infile("alumni.freire", ios::binary);
if(infile.is_open()){
infile.seekg(pos, ios::beg);
int size;
size = infile.get();
char charreg[size];
charreg[0] = size;
//testing what buffer gives me
for(int i = 1; i < size; i++){
charreg[i] = infile.get();
cout << charreg[i];
}
}
What am I doing wrong?
EDIT: to explain better what I did:
I get the entries on the first "code" from user input and use them as parameters when creating a "reg" class I implemented. The reg class then does (adequatly, I've already tested it) the conversion to strings, and calculates a hidden four-element char array containing instance size, name size, surname size and degree size. When the program writes the class on-file, it is written perfectly, as I showed in the second "code" section. (If you do the calculations you'll see '&' equals the size of the entire thing, for example). When I read it from the file, it appears differently on console for some reason. Different characters. But it reads the right amount of characters because "name", "surname" and "degree" appear correctly.
EDIT n2: I made "charreg[]" into an int array and printed it and the values are correct. I have no idea what's happening anymore.
EDIT n3: Apparently the reason I was getting the wrong chars is that I should have used unsigned chars...
The idea to write, as is, your structure is good. But your approach is wrong.
You must have something to separate your fields.
For example you know that your ID is 8 byte long, great ! You can read 8 bytes :
long long id;
read(fd, &id, 8);
In your example you got -24 because you read the first byte of the full id number.
But for the rest of the file, how can you know the length of the first name and the last name ?
You could read byte by byte until you find an null byte.
But I suggest you to use a more structured file.
For example, you can define a structure like this :
long long id; // 8 bytes
char firstname[256]; // 256 bytes
char lastname[256]; // 256 bytes
char sex; // 1 byte
int birthdate; // 4 bytes
With this structure you can read and write super easily :
struct my_struct s;
read(fd, &s, sizeof(struct my_struct)); // read 8+256+256+1+4 bytes
s.birthdate = 128;
write(fd, &s, sizeof(struct my_struct));// write the structure
Of course you loose the "variable length" of the first name and last name. Do you really need more than 100 chars for a name ?
In a case you really need, you could introduce an header over each variable length value. But you loose the ability to read everything at once.
long long id;
int foo_size;
char *foo;
And then to read it :
struct my_struct s;
read(fd, &s, 12); // read the header, 8 + 4 bytes
char foo[s.foo_size];
read(fd, &s, s.foo_size);
You should define what exactly you need to save. Define a precise data structure that you can easily deduce at read, avoid things like "oh, let's read until null-byte".
I used C function to explain you because it's much more representative. You know what you read and what you write.
Start to play with this, and then try the same with c++ streams/function
I don't know how you are writing back information to the file but here is how I would do that, I'm hoping this is a fairly simple way of doing it. Keep in mind I have no idea what kind of file you are actually working with.
long long id = 1000;
std::string name = "name";
std::string surname = "overflow";
std::string degree = "internet";
unsigned char sex = 'c';
int birthdate = 256;
ofstream outfile("test.txt", ios::binary);
if (outfile.is_open())
{
const char* idBytes = static_cast<char*>(static_cast<void*>(&id));
const char* nameBytes = name.c_str();
const char* surnameBytes = surname.c_str();
const char* degreeBytes = degree.c_str();
const char* birthdateBytes = static_cast<char*>(static_cast<void*>(&birthdate));
outfile.write(idBytes, sizeof(id));
outfile.write(nameBytes, name.length());
outfile.write(surnameBytes, surname.length());
outfile.write(degreeBytes, degree.length());
outfile.put(sex);
outfile.write(birthdateBytes, sizeof(birthdate));
outfile.flush();
outfile.close();
}
and here is how I am going to output it, which to me seems to be coming out as expected.
ifstream infile("test.txt", std::ifstream::ate | ios::binary);
if (infile.is_open())
{
std::size_t fileSize = infile.tellg();
infile.seekg(0);
for (int i = 0; i < fileSize; i++)
{
char c = infile.get();
std::cout << c;
}
std::cout << std::endl;
}
I'm trying to read in a .csv file filled with floats. I used this to build my code. However, the data reads in correctly but is read in as a string but I want to use the data as floats. If I try to use stof(string) I get an error that it is trying to convert a non number to a number. So I went the really long way and converted the string to a char and that to a float, which works but is VERY ugly. However, once all the data is read in and is printed out with a cout the program my crashes
trackBarFile.open("test2.csv");
std::string line, line2, line3;
int count;
std::string token;
float tokenNum,lineFloat,line2Float,line3Float;
char cstr[5],cstr2[5];
while (getline(trackBarFile, line,','))
{
cstr[line.size()+1];
strcpy(cstr, line.c_str());
lineFloat = atof(cstr);
getline(trackBarFile, line2,',');
cstr[line2.size()+1];
strcpy(cstr, line2.c_str());
line2Float = atof(cstr);
getline(trackBarFile, line3);
cstr2[line3.size()+1];
strcpy(cstr2, line3.c_str());
line3Float = atof(cstr2);
std::cout<<line<<","<<lineFloat<<" , "<<line2<<","<<line2Float<<" , "<<line3<<","<<line3Float<<std::endl;
}
trackBarFile.close();
It seems I have stumbled upon the answer to my own question. Thanks to the above questions I started looking for different ways to convert the string to a float. The +2 in the print out can be ignored, was my "pinch" to make sure I wasn't dreaming
trackBarFile.open("TrackBarSignal.csv");
std::ofstream fout;
fout.open("Output_ReadInCSV.txt");
std::string line, line2, line3;
int count;
float tokenNum,lineFloat,line2Float,line3Float;
while (getline(trackBarFile, line,',')&&getline(trackBarFile, line2,',')&&getline(trackBarFile, line3))
{
lineFloat = (float)atof(line.c_str());
line2Float = (float)atof(line2.c_str());
line3Float = (float)atof(line3.c_str());
std::cout<<line<<","<<lineFloat+2<<" , "<<line2<<","<<line2Float+2<<" , "<<line3<<","<<line3Float+2<<std::endl;
}
trackBarFile.close();
Given a decimal values (seconds and fractions thereof) as a string such as
std::string span = "ssss.nnnn" // ssss is value in seconds, nnnn is fractional seconds
What is the best way to convert it to a timeval structure (val.ts_sec and val.ts_usec) or a timespec structure (tv_sec and tv_nsec).
Most of the answers discuss converting values or are not C++. Some answers get very complex or set up classes which really is too much for this usage.
Obviously sscanf or istringstream can be used if the two values are separated by white space. However, is there a simple way of doing this if they are separated by a "." without looping over the character buffer searching for the "."
EDIT: As Borgleader rightly mentioned, simply reading into a double can incur precision loss if the timestamp becomes sufficiently large (larger than a million, give or take). A numerically stable way is
timeval v;
time_t seconds;
double fraction;
std::istringstream parser(span);
if(parser >> seconds >> std::noskipws >> fraction) {
v.tv_sec = seconds;
v.tv_usec = static_cast<suseconds_t>(fraction * 1e6);
}
Since now the fraction part is guaranteed to be small enough that the mantissa of an ieee-754 double will cover more than 9 decimal digits after the comma. One possible addition is
v.tv_usec = static_cast<suseconds_t>(fraction * 1e6 + 0.5); // rounding to nearest instead of down
depending on your use case.
If you decide to use string class and its functions If the number is always decimal, then I would suggest the following solution:
string span = "1234.123";
span += "000000";
size_t pos = span.find('.');
struct timeval val;
val.tv_sec = stol(span.substr(0,pos));
val.tv_usec = stol(span.substr(pos+1,6));
If the string may also get integer value without the dot '.' character then use
string span = "1234";
size_t pos = span.find('.');
struct timeval val;
val.tv_sec = stol( (pos!=string::npos)? span.substr(0,pos):span );
val.tv_usec = (pos!=string::npos)? stol((span+"000000").substr(pos+1,6)):0;
This solution also uses some c++11.
You can use strtok_s to split a string based off a delimiter. In your case would be "."
#include <iostream>
#include <string>
int main()
{
std::string span = "ssss.nnnn";
char * span1 = (char *)span.c_str();
char * pch = NULL;
char * context;
pch = strtok_s(span1, " .", &context);
while (pch != NULL)
{
printf("%s\n", pch);
pch = strtok_s(NULL, " .", &context);
}
return 0;
}
Output:
ssss
nnnn
I just found this as a possible answer. I would still like to find something else as well.
Parse (split) a string in C++ using string delimiter (standard C++)
strtok allows you to pass in multiple chars as delimiters. I bet if
you passed in ">=" your example string would be split correctly (even
though the > and = are counted as individual delimiters).
EDIT if you don't want to use c_str() to convert from string to char*,
you can use substr and find_first_of to tokenize.
string token, mystring("scott>=tiger");
while(token != mystring){
token = mystring.substr(0,mystring.find_first_of(">="));
mystring = mystring.substr(mystring.find_first_of(">=") + 1);
printf("%s ",token.c_str());
}
Update:
#Wintermute pointed out that the following code snippet would not work because of the possibility of leading zeros.
string span;
int sec;
int usec;
timeval inTime;
sscanf(span.c_str(), "%d.%d", &sec, &usec);
inTime.tv_sec = sec;
inTime.tv_usec = usec;
How can i conver from base64 string to hexa string (i'm working in ubuntu - c++ code). My hexa string I would like to be like 0x0c....and so on. Need help. Can someone please give me an exaple?Thx!
A quick solution that uses common (though not standard) functions:
std::string input = MY_ENCODED_STRING;
unsigned long decoded_value = strtol(input.c_str(), NULL, 64);
char buffer[100] = {0};
std::string output = itoa(decoded_value, buffer, 16);
boost::lexical_cast may be able to provide a more elegant solution (not sure on that one, though).
I'm parsing a string that follows a predictable pattern:
1 character
an integer (one or more digits)
1 colon
a string, whose length came from #2
For example:
s5:stuff
I can see easily how to parse this with PCRE or the like, but I'd rather stick to plain string ops for the sake of speed.
I know I'll need to do it in 2 steps because I can't allocate the destination string until I know its length. My problem is gracefully getting the offset for the start of said string. Some code:
unsigned start = 0;
char type = serialized[start++]; // get the type tag
int len = 0;
char* dest = NULL;
char format[20];
//...
switch (type) {
//...
case 's':
// Figure out the length of the target string...
sscanf(serialized + start, "%d", &len);
// <code type='graceful'>
// increment start by the STRING LENGTH of whatever %d was
// </code>
// Don't forget to skip over the colon...
++start;
// Build a format string which accounts for length...
sprintf(format, "%%%ds", len);
// Finally, grab the target string...
sscanf(serialized + start, format, string);
break;
//...
}
That code is roughly taken from what I have (which isn't complete because of the issue at hand) but it should get the point across. Maybe I'm taking the wrong approach entirely. What's the most graceful way to do this? The solution can either C or C++ (and I'd actually like to see the competing methods if there are enough responses).
You can use the %n conversion specifier, which doesn't consume any input - instead, it expects an int * parameter, and writes the number of characters consumed from the input into it:
int consumed;
sscanf(serialized + start, "%d%n", &len, &consumed);
start += consumed;
(But don't forget to check that sscanf() returned > 0!)
Use the %n format specifier to write the number of characters read so far to an integer argument.
Here's a C++ solution, it could be better, and is hard-coded specifically to deal with your example input, but shouldn't require much modification to get working.
std::stringstream ss;
char type;
unsigned length;
char dummy;
std::string value;
ss << "s5:Helloxxxxxxxxxxx";
ss >> type;
ss >> length;
ss >> dummy;
ss.width(length);
ss >> value;
std::cout << value << std::endl;
Disclaimer:
I'm a noob at C++.
You can probably just use atoi which will ignore the colon.
e.g. len = atoi(serialized + start);
The only thing with atoi is that if it returns zero it could mean either the conversion failed, or that the length was truly zero. So it's not always the most appropriate function.
if you replace you colon with a space scanf will stop on it and you can get the size malloc the size then run another scanf to get the rest of the string`
int main (int argc, const char * argv[]) {
char foo[20];
char *test;
scanf("%s",foo); //"hello world"
printf("foo = %s\n", foo);//prints hello
//get size
test = malloc(sizeof(char)* 10);//replace 10 with your string size
scanf("%s", test);
printf("test = %s\n", test);//prints world
return 0;
}
`
Seems like the format is overspecified... (using a variable length field to specify the length of a variable length field).
If you're using GCC, I'd suggest
if (sscanf(serialized,"%c%d:%as",&type,&len,&dest)<3) return -1;
/* use type, dest; ignore len */
free(dest);
return 0;