Re: istringstream Conversion Question
On Jul 31, 4:32 pm, mrc2...@cox.net (Mike Copeland) wrote:
I am using istringstring to convert data. For example,
int parseInt(string source, int start, int length)
{
int iResult;
if((start >= 0) && (start < source.length()))
{
istringstream myStream(source.substr(start, length));
myStream >> iResult;
}
return iResult;
}
where (hopefully) the parameters are valid. In my testing, I find that
if the parameters are NOT valid (start < 0 or > source.length()) or if
the data in source isn't numeric, the code either skips the conversion
(as it should) or the conversion fails. In those cases, the function's
return value is -858993460, which I gather is the unitialized value of
the integer variable iResult.
That's okay to a degree, but I'd like to be able to determine that=
an
error has occurred - and test for it in the calling logic. I can't fin=
d
any definition value for this default value, so I don't the
value/constant to test for, etc.
Given that atoi returns 0 for such errors, and given that I'd like=
a
more robust way of detecting errors (0 could be a legitimate conversion
result), I'd like to know what better solutions are available. Please
advise. TIA
The function is rather pointless. If someone wants to use string
streams to parse stuff, they should just do so directly.
Still, an improved version would be:
bool parseInt(const string& source, int start, int length, int&
result)
{
assert(start >= 0 && start < source.length());
istringstream myStream(source.substr(start, length));
myStream >> result;
return myStream.good();
}
If you want full control over the conversion and more detailed error
reporting, you should write your own function. Here's something I
wrote some time ago:
#include <string>
#include <exception>
#include <limits>
#include <assert.h>
class Integer
{
public:
static const int ALLOW_LEADING_WHITESPACE = 0x1;
static const int ALLOW_LEADING_SIGN = 0x2;
static const int ALL =
ALLOW_LEADING_WHITESPACE |
ALLOW_LEADING_SIGN
;
class OverflowException : public std::exception {};
class FormatException : public std::exception {};
template<class SignedInt>
static SignedInt ParseSigned(
const std::string& text,
std::string::const_iterator* endOfNumber = 0,
int base = 10,
int flags = 0
);
};
template<class SignedInt>
SignedInt Integer::ParseSigned(
const std::string& text,
std::string::const_iterator* endOfNumber,
int base,
int flags
)
{
using namespace std;
static_assert(numeric_limits<SignedInt>::is_specialized,
"numeric_limits<SignedInt> must be specialized");
static_assert(numeric_limits<SignedInt>::is_integer, "SignedInt must
be an integer type");
static_assert(numeric_limits<SignedInt>::is_signed, "SignedInt must
be a signed integer type");
assert(base >= 2 && base <= 36);
if (text.empty())
throw FormatException();
string::const_iterator iter = text.begin();
if (flags & ALLOW_LEADING_WHITESPACE)
{
static const char whitespace[] = " \f\n\r\t\v";
string::size_type i = text.find_first_not_of(whitespace);
if (i == string::npos)
throw FormatException();
iter += i;
}
bool isNegative = false;
if (flags & ALLOW_LEADING_SIGN)
{
if (*iter == '+')
{
++iter;
if (iter == text.end())
throw FormatException();
}
else if (*iter == '-')
{
isNegative = true;
++iter;
if (iter == text.end())
throw FormatException();
}
}
const string::const_iterator startOfNumber = iter;
SignedInt result = 0;
if (isNegative)
{
do
{
int digit;
if (*iter >= '0' && *iter <= '9')
digit = *iter - '0';
else if (*iter >= 'a' && *iter <= 'z')
digit = *iter - 'a' + 10;
else if (*iter >= 'A' && *iter <= 'Z')
digit = *iter - 'A' + 10;
else
break;
if (digit >= base)
break;
SignedInt next = result * base - digit;
if (next > result)
throw OverflowException();
result = next;
++iter;
}
while (iter != text.end());
}
else
{
do
{
int digit;
if (*iter >= '0' && *iter <= '9')
digit = *iter - '0';
else if (*iter >= 'a' && *iter <= 'z')
digit = *iter - 'a' + 10;
else if (*iter >= 'A' && *iter <= 'Z')
digit = *iter - 'A' + 10;
else
break;
if (digit >= base)
break;
SignedInt next = result * base + digit;
if (next < result)
throw OverflowException();
result = next;
++iter;
}
while (iter != text.end());
}
if (iter == startOfNumber)
throw FormatException();
if (endOfNumber)
*endOfNumber = iter;
return result;
}
(I was thinking about also writing a ParseUnsigned, but I never
actually needed it.)