C++ read in two numbers but no spaces, RINEX file - c++

I am trying to read in multiple numbers from lines in a RINEX file. The file number looks something like:
12345.67890
However, because of the RINEX formatting the 12345.6789 represents a measurement and the 0 at the end of the decimal actually represents something else. I am using the basic way to read in:
Rinexfile>>double_temp;
and I get double_temp=12345.67890 where I would like to do
Rinexfile>>double_temp>>int_temp;
and have double_temp=12345.6789 and int_temp=0. The formatting is always the same, ie 4 decimals belonging to the double and then an int and I am using VS2010
Thanks

You need more sophisticated approach:
std::string word;
Rinexfile >> word;
std::size_t dot_pos = str.find('.');
if (dot_pos != std::string::npos) {
std::string doublePart = word.substr(0, dot_pos + 1 + 4); // 4 decimals
std::string intPart = word.substr(dot_pos + 1 + 4);
std::istringstream is(doublePart), is2(intPart);
is >> double_temp;
is2 >> int_temp;
}
This reads an input in form of single std::string and divides it into 2 parts: doublePart is a string that includes '.' sign and 4 letters that follows. intPart is the rest of the word. Temporary instances of std::istringstream are constructed to retrieve the values.
Note: Additional error handling might be needed.

The default input format for floating points will read as many digits after the decimal point as there are. However, it is possible to change the functions used to parse the values by using a custom std::num_get<char> facet and installing a suitable locale. Here is how this could roughly look (currently I can't easily test the code):
#include <locale>
#include <cstdlib>
#include <cctype>
struct num_get
: std::num_get<char>
{
iter_type do_get(iter_type it, iter_type end, std::ios_base& fmt,
std::ios_base::iostate& err, double& value) const {
char buf[64];
char* to(buf), to_end(buf + 63);
for (; it != end && to != to_end
&& std::isdigit(static_cast<unsigned char>(*it)); ++it, ++to) {
*to = *it;
}
if (it != end && *it == '.') {
*to = *it;
++it;
++to;
}
to_end = to_end - to < 4? to_end - to: to + 4;
for (; it != end && to != to_end
&& std::isdigit(static_cast<unsigned char>(*it)); ++it, ++to) {
*to = *it;
}
*to = 0;
if (std::strtod(buf, 0, &value) != to) {
err |= std::ios_base::failbit;
}
return it;
}
};
With this decoder (which may want to get a bit more error checking, though) you'd just set up you stream and then read as normal:
in.imbue(std::locale(std::locale(), new num_get));
double dval;
int ival;
if (in >> dval >> ival) {
std::cout << "read dval=" << dval << " ival=" << ival << '\n';
}

If you don't want to mess with strings, you could read integral and decimal part separately and get the data you need like this:
int i, d;
cin >> i;
cin.get(); // skip decimal point
cin >> d;
double value = i + (d / 10) / 10000.0;
int something_else = d % 10;
cout << setprecision(4) << fixed << value << endl << something_else;
(it won't work if "something else" can be longer than 1 digit)

Related

How to convert ASCII Number to Integer which are taken from a file

Four digit numbers stored in a file are written in ASCII and separated by "Space". How do I read them as Integers?
Example file:
53545153 49575150 56485654 53565257 52555756 51534850 56575356 56505055 55525453
Here is what I tried:
ifstream infile("afile2.txt");
if (infile.is_open())
{
string str2;
char c;
while (!infile.eof())
{
getline(infile, str2, ' ');
for (std::string::iterator it = str2.begin(); it != str2.end(); ++it)
cout << (char)*it;
cout << " ";
}
}
infile.close();
In the above code (char)*it is picking only first digit but ASCII number start at 2 digit number i.e. 48.
Four digit numbers stored in a file are written in ASCII and separated by "Space", How do I read them as Integers. Example file: 53545153 49575150 56485654 53565257 52555756 51534850 56575356 56505055 55525453
Those look like 8 digit numbers.
To read a space separated number from a file simple use operator>> from a stream to an integer.
int value;
if (stream >> value) {
// Successfully read a number.
}
If you want to read all the values from a file. You can use a loop:
int value;
while (stream >> value) {
// Enter the body of the loop each time a number is read.
}
Note: Your usage of eof() is bad practice:
while (!infile.eof()) {
// If you enter here the file may be open and readable
// BUT there may be no data left in the file and thus the next
// attempt to read will fail if there is no data.
//
// This happens because the last successful read will read up-to
// but not past the EOF. So you have read all the data but not read
// past the EOF so eof() will return false.
}
More Info
So how do we read 2 digit numbers from groups of 8 digit larger numbers that are space separated.
Well we want to make it work like standard stream readding so we still want to use the operator>> to read from the stream. But none of the built in types read two digit numbers. So we need to define our own class that will read a two digit number.
struct TwoDigit
{
int value; // store the result here
operator int() {return value;} // Convert TwoDigit to integer
};
std::ostream& operator<<(std::ostream& str, TwoDigit const& data) {
str << data.value; // You can do something more complicated
// for printing but its not the current question
// so I am just going to dump the value out.
}
std::istream& operator>>(std::istream& str, TwoDigit& data) {
char c1 = 'X';
char c2 = 'Y';
if (str >> c1 >> c2) {
// successfully read two characters from the stream.
// Note >> automatically drops white space (space return etc)
// so we don't need to worry about that.
if (('0' <= c1 && c1 <= '9') && ('0' <= c2 && c2 <= '9')) {
// We have all good data.
// So let us update the vale.
data.value = ((c1 - '0') * 10) + (c2 - '0');
}
else {
// We have bad data read from the stream.
// So lets mark the stream as bad;
str.clear(std::ios::failbit);
}
}
return str;
}
Now in your code you can simply read
TwoDigit data;
if (stream >> data) {
// Read a single two digit value correctly.
}
// or for a loop:
while(stream >> data) {
// Keep reading data from the stream.
// Each read will consume two digits.
}
// or if you want to fill a vector from a stream.
std::vector<TwoDigit> data(std::istream_iterator<TwoDigit>(stream),
std::istream_iterator<TwoDigit>());
// You can even create a vector of int just as easily.
// Because the TwoDigit has an `operator int()` to convert to int.
std::vector<int> data(std::istream_iterator<TwoDigit>(stream),
std::istream_iterator<TwoDigit>());
This could be an approach if I've understood the problem correctly.
#include <cmath>
#include <iostream>
#include <string>
#include <vector>
std::vector<int> conv(std::istream& is) {
std::vector<int> retval;
std::string group;
while(is >> group) { // read "53545153" for example
int mul =
static_cast<int>(std::pow(10, (group.size() / 2) - 1)); // start at 1000
int res = 0;
for(size_t i = 0; i < group.size(); i += 2, mul /= 10) {
// convert "53" to dec ASCII char 53 ('5') and then to an int 5 and
// multiply by 1000 (mul)
res += (((group[i] - '0') * 10 + (group[i + 1] - '0')) - '0') * mul;
}
retval.emplace_back(res); // store
}
return retval;
}
Testing the function:
#include <sstream>
int main() {
std::istringstream is(
"53545153 49575150 56485654 53565257 52555756 51534850 56575356 56505055 55525453");
auto r = conv(is);
for(int x : r) {
std::cout << x << "\n";
}
}
Output:
5635
1932
8086
5849
4798
3502
8958
8227
7465

How to "Fold a word" from a string. EX. "STACK" becomes "SKTCA". C++

I'm trying to figure out how to can fold a word from a string. For example "code" after the folding would become "ceod". Basically start from the first character and then get the last one, then the second character. I know the first step is to start from a loop, but I have no idea how to get the last character after that. Any help would be great. Heres my code.
#include <iostream>
using namespace std;
int main () {
string fold;
cout << "Enter a word: ";
cin >> fold;
string temp;
string backwards;
string wrap;
for (unsigned int i = 0; i < fold.length(); i++){
temp = temp + fold[i];
}
backwards= string(temp.rbegin(),temp.rend());
for(unsigned int i = 0; i < temp.length(); i++) {
wrap = fold.replace(backwards[i]);
}
cout << wrap;
}
Thanks
#Supreme, there are number of ways to do your task and I'm going to post one of them. But as #John had pointed you must try your own to get it done because real programming is all about practicing a lot. Use this solution just as a reference of one possibility and find many others.
int main()
{
string in;
cout <<"enter: "; cin >> in;
string fold;
for (int i=0, j=in.length()-1; i<in.length()/2; i++, j--)
{
fold += in[i];
fold += in[j];
}
if( in.length()%2 != 0) // if string lenght is odd, pick the middle
fold += in[in.length()/2];
cout << endl << fold ;
return 0;
}
good luck !
There are two approaches to this form of problem, a mathematically exact method would be to create a generator function which returns the number in the correct order.
An easier plan would be to modify the string to solve practically the problem.
Mathematical solution
We want a function which returns the index in the string to add. We have 2 sequences - increasing and decreasing and they are interleaved.
sequence 1 :
0, 1 , 2, 3.
sequence 2
len-1, len-2, len-3, len-4.
Given they are interleaved, we want even values to be from sequence 1 and odd values from sequence 2.
So our solution would be to for a given new index, choose which sequence to use, and then return the next value from that sequence.
int generator( int idx, int len )
{
ASSERT( idx < len );
if( idx %2 == 0 ) { // even - first sequence
return idx/2;
} else {
return (len- (1 + idx/2);
}
}
This can then be called from a function fold...
std::string fold(const char * src)
{
std::string result;
std::string source(src);
for (size_t i = 0; i < source.length(); i++) {
result += source.at(generator(i, source.length()));
}
return result;
}
Pratical solution
Although less efficient, this can be easier to think about. We are taking either the first or the last character of a string. This we will do using string manipulation to get the right result.
std::string fold2(const char * src)
{
std::string source = src;
enum whereToTake { fromStart, fromEnd };
std::string result;
enum whereToTake next = fromStart;
while (source.length() > 0) {
if (next == fromStart) {
result += source.at(0);
source = source.substr(1);
next = fromEnd;
}
else {
result += source.at(source.length() - 1); // last char
source = source.substr(0, source.length() - 1); // eat last char
next = fromStart;
}
}
return result;
}
You can take advantage of the concept of reverse iterators to write a generic algorithm based on the solution presented in Usman Riaz answer.
Compose your string picking chars from both the ends of the original string. When you reach the center, add the char in the middle if the number of chars is odd.
Here is a possible implementation:
#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <algorithm>
#include <iterator>
template <class ForwardIt, class OutputIt>
OutputIt fold(ForwardIt source, ForwardIt end, OutputIt output)
{
auto reverse_source = std::reverse_iterator<ForwardIt>(end);
auto reverse_source_end = std::reverse_iterator<ForwardIt>(source);
auto source_end = std::next(source, std::distance(source, end) / 2);
while ( source != source_end )
{
*output++ = *source++;
*output++ = *reverse_source++;
}
if ( source != reverse_source.base() )
{
*output++ = *source;
}
return output;
}
int main() {
std::vector<std::pair<std::string, std::string>> tests {
{"", ""}, {"a", "a"}, {"stack", "sktca"}, {"steack", "sktcea"}
};
for ( auto const &test : tests )
{
std::string result;
fold(
std::begin(test.first), std::end(test.first),
std::back_inserter(result)
);
std::cout << (result == test.second ? " OK " : "FAILED: ")
<< '\"' << test.first << "\" --> \"" << result << "\"\n";
}
}

How to get data from user input?

I have a QTableWidget where the user inputs complex numbers in various styles.
For example, the complex number (-15 + 8.14i) can be written like:
-15 + 8.14i
-15+8.14j
-15 +j 8,14
-15+ i8,14
i can also be j!
Both values can be big (they are saved as double) and also negative. They can be written with "," and "." (so 3.14 and 3,14 are ment to be equal). There should be an error message when the user enters the number incorrectly.
CKomplex fromString(QString str) { // ckomplex is my custom class for complex numbers
double numReal, numImag;
QString strNew = "";
// delete all spaces
for (int i= 0; i< str.length(); i++) {
if (!str[i].isSpace()) {
strNew += str[i];
}
}
QString part1 = "";
int index;
// get the first number
for (int i= 0; i < strNew.length(); i++) { // iterate string
if (strNew[i] != '+' && strNew[i] != '-') {
part1 += strNew[i];
} else { // e.g.: 5 + 3j -> the loop is at the "+"
if (i != 0) {
index = i; // save index at "+" to start for next number
break;
}
}
}
numReal = part1.toDouble();
QString part2 = "";
// get the second number
for (int i= index; i < strNew.length(); i++) {
if (strNew[i].isDigit() || strNew[i] == '+' || strNew[i] == '-' || strNew[i] == '.' || strNew[i] == ',') { // ignore j or i
part2 += strNew[i];
}
}
numImag = part2.toDouble();
return CKomplex(numReal, numImag);
}
This does work for basic input. But is not very fast or readable or useful. And it does cover just few possibilities of input (stuff like "-3 - 5,14" doesnt work). Is there an easier way to convert the string into a complex number without having so much loops and variables?
A single regular expression could parse each of the lines:
#include <string>
#include <sstream>
#include <vector>
#include <iterator>
#include <regex>
#include <iostream>
#include <iomanip>
#include <exception>
class CKomplex {
public:
CKomplex(double numReal, double numImag) : numReal{numReal}, numImag{numImag} {}
double numReal;
double numImag;
};
auto input_text{
R"(-15 + 8.14i
-15+8.14j
-15 +j 8,14
-15+ i8,14
bad line here
+23.4-j24
-35+42.3j
+24i
+2.342j
+24.523-i 432,52
24.523-i 432,52
23.4-j24
35+42.3j
24i
2.342j)"};
CKomplex fromString(std::string str) {
double numReal{};
double numImag{};
std::regex r{R"(([+-]?) *([ij]?) *(\d+)[.,]?(\d*)([ij])?)"}; // 6 groups
std::istringstream iss(str);
auto it = std::sregex_iterator(str.begin(), str.end(), r);
auto end = std::sregex_iterator();
if(it == end || it->size() != 6)
throw std::runtime_error("Could not parse line containing the following text: " + str);
for(; it != end; ++it) {
auto match = *it;
auto sign = match[1].str();
auto iorj_pre = match[2].str();
auto decimal = match[3].str();
auto fraction = match[4].str();
auto iorj_post = match[5].str();
double val{sign == "-" ? -1.F : 1.F};
val *= std::stod(decimal + "." + fraction);
if(iorj_pre == "i" || iorj_pre == "j" || iorj_post == "i" || iorj_post == "j")
numImag += val;
else
numReal += val;
}
return{numReal,numImag};
}
std::ostream& operator<<(std::ostream& os, const CKomplex& complex_number)
{
os << std::showpos << "(" << complex_number.numReal << " " << complex_number.numImag << "i)";
return os;
}
int main()
{
std::istringstream input_stream{input_text};
for(std::string line{}; std::getline(input_stream, line);) {
try { std::cout << std::setw(20) << line << ": " << fromString(line) << '\n'; }
catch(std::exception& e) { std::cout << e.what() << '\n'; }
}
return 0;
}
Produces (live demo):
-15 + 8.14i: (-15 +8.14i)
-15+8.14j: (-15 +8.14i)
-15 +j 8,14: (-15 +8.14i)
-15+ i8,14: (-15 +8.14i)
Could not parse line containing the following text: bad line here
+23.4-j24: (+23.4 -24i)
-35+42.3j: (-35 +42.3i)
+24i: (+0 +24i)
+2.342j: (+0 +2.342i)
+24.523-i 432,52: (+24.523 -432.52i)
24.523-i 432,52: (+24.523 -432.52i)
23.4-j24: (+23.4 -24i)
35+42.3j: (+35 +42.3i)
24i: (+0 +24i)
2.342j: (+0 +2.342i)

Complex algorithm to extract numbers/number range from a string

I am working on a algorithm where I am trying the following output:
Given values/Inputs:
char *Var = "1-5,10,12,15-16,25-35,67,69,99-105";
int size = 29;
Here "1-5" depicts a range value, i.e. it will be understood as "1,2,3,4,5" while the values with just "," are individual values.
I was writing an algorithm where end output should be such that it will give complete range of output as:
int list[]=1,2,3,4,5,10,12,15,16,25,26,27,28,29,30,31,32,33,34,35,67,69,99,100,101,102,103,104,105;
If anyone is familiar with this issue then the help would be really appreciated.
Thanks in advance!
My initial code approach was as:
if(NULL != strchr((char *)grp_range, '-'))
{
int_u8 delims[] = "-";
result = (int_u8 *)strtok((char *)grp_range, (char *)delims);
if(NULL != result)
{
start_index = strtol((char*)result, (char **)&end_ptr, 10);
result = (int_u8 *)strtok(NULL, (char *)delims);
}
while(NULL != result)
{
end_index = strtol((char*)result, (char**)&end_ptr, 10);
result = (int_u8 *)strtok(NULL, (char *)delims);
}
while(start_index <= end_index)
{
grp_list[i++] = start_index;
start_index++;
}
}
else if(NULL != strchr((char *)grp_range, ','))
{
int_u8 delims[] = ",";
result = (unison_u8 *)strtok((char *)grp_range, (char *)delims);
while(result != NULL)
{
grp_list[i++] = strtol((char*)result, (char**)&end_ptr, 10);
result = (int_u8 *)strtok(NULL, (char *)delims);
}
}
But it only works if I have either "0-5" or "0,10,15". I am looking forward to make it more versatile.
Here is a C++ solution for you to study.
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
int ConvertString2Int(const string& str)
{
stringstream ss(str);
int x;
if (! (ss >> x))
{
cerr << "Error converting " << str << " to integer" << endl;
abort();
}
return x;
}
vector<string> SplitStringToArray(const string& str, char splitter)
{
vector<string> tokens;
stringstream ss(str);
string temp;
while (getline(ss, temp, splitter)) // split into new "lines" based on character
{
tokens.push_back(temp);
}
return tokens;
}
vector<int> ParseData(const string& data)
{
vector<string> tokens = SplitStringToArray(data, ',');
vector<int> result;
for (vector<string>::const_iterator it = tokens.begin(), end_it = tokens.end(); it != end_it; ++it)
{
const string& token = *it;
vector<string> range = SplitStringToArray(token, '-');
if (range.size() == 1)
{
result.push_back(ConvertString2Int(range[0]));
}
else if (range.size() == 2)
{
int start = ConvertString2Int(range[0]);
int stop = ConvertString2Int(range[1]);
for (int i = start; i <= stop; i++)
{
result.push_back(i);
}
}
else
{
cerr << "Error parsing token " << token << endl;
abort();
}
}
return result;
}
int main()
{
vector<int> result = ParseData("1-5,10,12,15-16,25-35,67,69,99-105");
for (vector<int>::const_iterator it = result.begin(), end_it = result.end(); it != end_it; ++it)
{
cout << *it << " ";
}
cout << endl;
}
Live example
http://ideone.com/2W99Tt
This is my boost approach :
This won't give you array of ints, instead a vector of ints
Algorithm used: (nothing new)
Split string using ,
Split the individual string using -
Make a range low and high
Push it into vector with help of this range
Code:-
#include<iostream>
#include<vector>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
int main(){
std::string line("1-5,10,12,15-16,25-35,67,69,99-105");
std::vector<std::string> strs,r;
std::vector<int> v;
int low,high,i;
boost::split(strs,line,boost::is_any_of(","));
for (auto it:strs)
{
boost::split(r,it,boost::is_any_of("-"));
auto x = r.begin();
low = high =boost::lexical_cast<int>(r[0]);
x++;
if(x!=r.end())
high = boost::lexical_cast<int>(r[1]);
for(i=low;i<=high;++i)
v.push_back(i);
}
for(auto x:v)
std::cout<<x<<" ";
return 0;
}
You're issue seems to be misunderstanding how strtok works. Have a look at this.
#include <string.h>
#include <stdio.h>
int main()
{
int i, j;
char delims[] = " ,";
char str[] = "1-5,6,7";
char *tok;
char tmp[256];
int rstart, rend;
tok = strtok(str, delims);
while(tok != NULL) {
for(i = 0; i < strlen(tok); ++i) {
//// range
if(i != 0 && tok[i] == '-') {
strncpy(tmp, tok, i);
rstart = atoi(tmp);
strcpy(tmp, tok + i + 1);
rend = atoi(tmp);
for(j = rstart; j <= rend; ++j)
printf("%d\n", j);
i = strlen(tok) + 1;
}
else if(strchr(tok, '-') == NULL)
printf("%s\n", tok);
}
tok = strtok(NULL, delims);
}
return 0;
}
Don't search. Just go through the text one character at a time. As long as you're seeing digits, accumulate them into a value. If the digits are followed by a - then you're looking at a range, and need to parse the next set of digits to get the upper bound of the range and put all the values into your list. If the value is not followed by a - then you've got a single value; put it into your list.
Stop and think about it: what you actually have is a comma
separated list of ranges, where a range can be either a single
number, or a pair of numbers separated by a '-'. So you
probably want to loop over the ranges, using recursive descent
for the parsing. (This sort of thing is best handled by an
istream, so that's what I'll use.)
std::vector<int> results;
std::istringstream parser( std::string( var ) );
processRange( results, parser );
while ( isSeparator( parser, ',' ) ) {
processRange( results, parser );
}
with:
bool
isSeparator( std::istream& source, char separ )
{
char next;
source >> next;
if ( source && next != separ ) {
source.putback( next );
}
return source && next == separ;
}
and
void
processRange( std::vector<int>& results, std::istream& source )
{
int first = 0;
source >> first;
int last = first;
if ( isSeparator( source, '-' ) ) {
source >> last;
}
if ( last < first ) {
source.setstate( std::ios_base::failbit );
}
if ( source ) {
while ( first != last ) {
results.push_back( first );
++ first;
}
results.push_back( first );
}
}
The isSeparator function will, in fact, probably be useful in
other projects in the future, and should be kept in your
toolbox.
First divide whole string into numbers and ranges (using strtok() with "," delimiter), save strings in array, then, search through array looking for "-", if it present than use sscanf() with "%d-%d" format, else use sscanf with single "%d" format.
Function usage is easily googling.
One approach:
You need a parser that identifies 3 kinds of tokens: ',', '-', and numbers. That raises the level of abstraction so that you are operating at a level above characters.
Then you can parse your token stream to create a list of ranges and constants.
Then you can parse that list to convert the ranges into constants.
Some code that does part of the job:
#include <stdio.h>
// Prints a comma after the last digit. You will need to fix that up.
void print(int a, int b) {
for (int i = a; i <= b; ++i) {
printf("%d, ", i);
}
}
int main() {
enum { DASH, COMMA, NUMBER };
struct token {
int type;
int value;
};
// Sample input stream. Notice the sentinel comma at the end.
// 1-5,10,
struct token tokStream[] = {
{ NUMBER, 1 },
{ DASH, 0 },
{ NUMBER, 5 },
{ COMMA, 0 },
{ NUMBER, 10 },
{ COMMA, 0 } };
// This parser assumes well formed input. You have to add all the error
// checking yourself.
size_t i = 0;
while (i < sizeof(tokStream)/sizeof(struct token)) {
if (tokStream[i+1].type == COMMA) {
print(tokStream[i].value, tokStream[i].value);
i += 2; // skip to next number
}
else { // DASH
print(tokStream[i].value, tokStream[i+2].value);
i += 4; // skip to next number
}
}
return 0;
}

Convert hexadecimal string with leading "0x" to signed short in C++?

I found the code to convert a hexadecimal string into a signed int using strtol, but I can't find something for a short int (2 bytes). Here' my piece of code :
while (!sCurrentFile.eof() )
{
getline (sCurrentFile,currentString);
sOutputFile<<strtol(currentString.c_str(),NULL,16)<<endl;
}
My idea is to read a file with 2 bytes wide values (like 0xFFEE), convert it to signed int and write the result in an output file. Execution speed is not an issue.
I could find some ways to avoid the problem, but I'd like to use a "one line" solution, so maybe you can help for this :)
Edit : The files look like this :
0x0400
0x03fe
0x03fe
...
Edit : I already tried with the hex operator, but I still have to convert the string to an integer before doing so.
// This won't work as currentString is not an integer
myInt << std::hex << currentString.c_str();
This should be simple:
std::ifstream file("DataFile");
int value;
while(file >> std::hex >> value) // Reads a hex string and converts it to an int.
{
std::cout << "Value: " << std::hex << value << "\n";
}
While we are talking about files:
You should NOT do this:
while (!sCurrentFile.eof() )
{
getline (sCurrentFile,currentString);
... STUFF ...
}
This is because when you read the last line it does NOT set the EOF. So when you loop around and then read the line after the last line, getline() will fail and you will be doing STUFF on what was in currentString from the last time it was set up. So in-effect you will processes the last line twice.
The correct way to loop over a file is:
while (getline(sCurrentFile,currentString))
{
// If the get fails then you have read past EOF and loop is not entered.
... STUFF ...
}
You can probably use stringtream class's >> operator with hex manipulator.
Have you considered sscanf with the "%hx" conversion qualifier?
// convert unsigned-integer to it's hexadecimal string represention
// 0x12345678 -> '12345678'
// N is BYTE/WORD/UINT/ULONGLONG
// T is char or wchar_t
template <class N, class T> inline T* UnsignedToHexStr(N n , // [i ]
T* pcStr , // [i/o] filled with string
UINT nDigits , // [i ] number of digits in output string / 0 (auto)
bool bNullTerminate ) // [i ] whether to add NULL termination
{
if ((N)-1 < (N)1) // if type of N is floating-point / signed-integer
if (::IsDebuggerPresent())
{
::OutputDebugString(_T("UnsignedToHexStr: Incorrect type passed\n"));
::DebugBreak();
}
if (!nDigits)
nDigits= GetUnsignedHexDigits(n);
if (1 == sizeof(T))
{
const char _czIntHexConv[]= "0123456789ABCDEF";
for (int i= nDigits-1; i>= 0; i--)
{
char* pLoc= (char*)&pcStr[i];
*pLoc= _czIntHexConv[n & 0x0F];
n >>= 4;
}
}
else
{
const wchar_t _czIntHexConv[]= L"0123456789ABCDEF";
for (int i= nDigits-1; i>= 0; i--)
{
wchar_t* pLoc= (wchar_t*)&pcStr[i];
*pLoc= _czIntHexConv[n & 0x0F];
n >>= 4;
}
}
if (bNullTerminate)
pcStr[nDigits]= 0;
return pcStr;
}
// --------------------------------------------------------------------------
// convert unsigned-integer in HEX string represention to it's numerical value
// '1234' -> 0x1234
// N is BYTE/WORD/UINT/ULONGLONG
// T is char or wchar_t
template <class N, class T> inline bool HexStrToUnsigned(const T* pczSrc ,
N& n ,
bool bSpecificTerminator= false, // whether string should terminate with specific terminating char
T cTerminator = 0 ) // specific terminating char
{
n= 0;
if (!pczSrc)
return false;
while ((32 == *pczSrc) || (9 == *pczSrc))
pczSrc++;
bool bLeadZeros= *pczSrc == _T('0');
while (*pczSrc == _T('0')) // skip leading zeros
pczSrc++;
BYTE nMaxDigits= 2*sizeof(N);
BYTE nDigits = 0 ;
while (true)
{
if ( (*pczSrc >= _T('0')) && (*pczSrc <= _T('9')))
{ if (nDigits==nMaxDigits) return false; n= (n<<4) + (*pczSrc-_T('0') ); pczSrc++; nDigits++; continue; }
if ( (*pczSrc >= _T('A')) && (*pczSrc <= _T('F')))
{ if (nDigits==nMaxDigits) return false; n= (n<<4) + (*pczSrc-_T('A')+10); pczSrc++; nDigits++; continue; }
if ( (*pczSrc >= _T('a')) && (*pczSrc <= _T('f')))
{ if (nDigits==nMaxDigits) return false; n= (n<<4) + (*pczSrc-_T('a')+10); pczSrc++; nDigits++; continue; }
if (bSpecificTerminator)
if (*pczSrc != cTerminator)
return false;
break;
}
return (nDigits>0) || bLeadZeros; // at least one digit
}
If you're sure the data can be trusted from currentString.c_str(), then you could also easily do
myInt << std::hex << atoi(currentString.c_str());
If you know the data is always going to be in that format, couldn't you just do something like:
myInt << std::hex << currentString.c_str() +2; // skip the leading "0x"