Converting a substring to Integer

S

sparkydarky

I have a bunch of strings in a database that have in them a number I
want to extract. Here's the example code I've been working with:

AnsiString tmp = "AMjsdfdsdfj 457756 some description";
int firstDelim = 0;
int secondDelim = 0;

for(int i=0; i<=tmp.Length(); i++)
{
if(IsDelimiter(" ", tmp, i));
{
if ( firstDelim == 0 )
firstDelim = i;
else
{
secondDelim = i;
break;
}
}
if ( secondDelim > 0 )
break;
}
int str_length = secondDelim - firstDelim;
ShowMessage(tmp.SubString(firstDelim, str_length));

Can someone give me a hint how to get this to work? Is my code way
off, or is there a better way to do it? it's only about 1500 records
I need to do this on, so speed is not of greatest importance.

Mark
 
A

AnonMail2005

I have a bunch of strings in a database that have in them a number I
want to extract.  Here's the example code I've been working with:

                AnsiString tmp = "AMjsdfdsdfj 457756 some description";
                int firstDelim = 0;
                int secondDelim = 0;

                for(int i=0; i<=tmp.Length(); i++)
                {
                        if(IsDelimiter(" ", tmp, i));
                        {
                                if ( firstDelim == 0 )
                                        firstDelim = i;
                                else
                                {
                                        secondDelim = i;
                                        break;
                                }
                        }
                        if ( secondDelim > 0 )
                        break;
                }
                int str_length = secondDelim - firstDelim;
                ShowMessage(tmp.SubString(firstDelim, str_length));

Can someone give me a hint how to get this to work?  Is my code way
off, or is there a better way to do it?  it's only about 1500 records
I need to do this on, so speed is not of greatest importance.

Mark

Without even looking at std::string documentation I can tell you
that finding delimiters and subtrings are member functions.
Instead of looping, just use those.

HTH
 
C

Christopher

I have a bunch of strings in a database that have in them a number I
want to extract. Here's the example code I've been working with:

AnsiString tmp = "AMjsdfdsdfj 457756 some description";
int firstDelim = 0;
int secondDelim = 0;

for(int i=0; i<=tmp.Length(); i++)
{
if(IsDelimiter(" ", tmp, i));
{
if ( firstDelim == 0 )
firstDelim = i;
else
{
secondDelim = i;
break;
}
}
if ( secondDelim > 0 )
break;
}
int str_length = secondDelim - firstDelim;
ShowMessage(tmp.SubString(firstDelim, str_length));

Can someone give me a hint how to get this to work? Is my code way
off, or is there a better way to do it? it's only about 1500 records
I need to do this on, so speed is not of greatest importance.

Mark


use a stringstream
put what you want to convert into the stringstream using operator <<
take what you want to convert out of the stringstream and attempt the
conversion using operator >>
check the fail bit to see if the conversion was successful

std::string text = "123";
int number;
std::stringstream converter;

converter << text;
converter >> number;

For the "substring" part of your question, use some creativity and
remember the effect of whitespace in data being inserted and extracted
from an iostream.
 
R

Reetesh Mukul

You can try this:-

#include <iostream>
#include <sstream>
#include <cctype>

int main()
{
std::string s = "dsdhjsahdk dsdjdsaj 36782367 sdjdhak";

int j = 0;
std::stringstream cstr;
cstr << s;
int i = 0;
char ch;

while( cstr >> ch )
{
if( std::isdigit(ch) )
{
cstr.putback(ch);
break;
}

if( ( j = s.find(" ",j) )== std::string::npos )
{
cstr.seekg(-1);
break;
}

cstr.seekg(++j, std::ios::beg);

}

if(cstr)
{
cstr >> i;
}
std::cout << i;

return 0;
}


With Regards,
Reetesh Mukul
 
C

Christopher

You can try this:-

#include <iostream>
#include <sstream>
#include <cctype>

int main()
{
std::string s = "dsdhjsahdk dsdjdsaj 36782367 sdjdhak";

int j = 0;
std::stringstream cstr;
cstr << s;
int i = 0;
char ch;

while( cstr >> ch )
{
if( std::isdigit(ch) )
{
cstr.putback(ch);
break;
}

if( ( j = s.find(" ",j) )== std::string::npos )
{
cstr.seekg(-1);
break;
}

cstr.seekg(++j, std::ios::beg);

}

if(cstr)
{
cstr >> i;
}
std::cout << i;

return 0;

}

With Regards,
Reetesh Mukul

Depending on how he is using the contents, it would be much more
efficient to assign the entire thing to the stringstream and keep
extracting int type until failbit it set. When it is set, clear it and
extract it to string type. Repeat until eof bit is set.

The solution you posted may not be useful if the OP actually wants to
do something with the non integers.. at least not efficient
It may also be error prone if the OP wants to extract strings that
contain numbers in them...Example: hello#1

Where as if he knows the text will be used for extracting either text
or ints, seperated by whitespace, than he can try to extract an int
and extract a string when int extraction fails. That we he is able to
use the entire contents in one swoop.

Of course, the OP didn't really give specifics.
 
D

Daniel T.

sparkydarky said:
I have a bunch of strings in a database that have in them a number I
want to extract. Here's the example code I've been working with:

AnsiString tmp = "AMjsdfdsdfj 457756 some description";

What is an "AnsiString"?
int firstDelim = 0;
int secondDelim = 0;

for(int i=0; i<=tmp.Length(); i++)
{

What exactly does "IsDelimiter" do?
if(IsDelimiter(" ", tmp, i));
{
if ( firstDelim == 0 )
firstDelim = i;
else
{
secondDelim = i;
break;
}
}
if ( secondDelim > 0 )
break;
}
int str_length = secondDelim - firstDelim;
ShowMessage(tmp.SubString(firstDelim, str_length));

Can someone give me a hint how to get this to work?

I'm not entirely sure what you think the above should do in the first
place. You leave a lot to be assumed... My assumptions: the various
parts of the string are separated by at least one space character, that
AnsiString can be inserted into a stringstream, and that you only want
to extract the first number in the string... There might be some other
assumptions I didn't think of.

int extractNumber( const string& str )
{
int result = 0;
stringstream ss( str );
while ( !( ss >> result ) ) {
if ( !ss.eof() ) {
ss.clear();
ss.ignore( numeric_limits<streamsize>::max(), ' ' );
}
else {
throw runtime_error( "no number" );
}
}
return result;
}

What the code does. Put the string into a stringstream, then attempt to
extract a number from it. For as long as we can't extract a number: if
we aren't at the end of the stream, clear the stream, scan to the next
space, and try again. Otherwise, throw an error indicating that no
number was found.
 
D

Daniel T.

Reetesh Mukul said:
You can try this:-

#include <iostream>
#include <sstream>
#include <cctype>

int main()
{
std::string s = "dsdhjsahdk dsdjdsaj 36782367 sdjdhak";

int j = 0;
std::stringstream cstr;
cstr << s;
int i = 0;
char ch;

while( cstr >> ch )
{
if( std::isdigit(ch) )
{
cstr.putback(ch);
break;
}
From here:
if( ( j = s.find(" ",j) )== std::string::npos )
{
cstr.seekg(-1);
break;
}

cstr.seekg(++j, std::ios::beg);
to here. Is this block of code necessary?
}

if(cstr)
{
cstr >> i;
}
std::cout << i;

return 0;
}

Wouldn't this be a simpler way of doing the same thing?

int main()
{
std::string s = "dsdhjsahdk dsdjdsaj 36782367 sdjdhak";

int i = 0;
std::stringstream cstr( s );
char ch = 0;
while( cstr >> ch && !isdigit( ch ) )
{ }
cstr.putback( ch );
cstr >> i;
cout << i;
}
 
J

James Kanze

I have a bunch of strings in a database that have in them a
number I want to extract. Here's the example code I've been
working with:
AnsiString tmp = "AMjsdfdsdfj 457756 some description";
int firstDelim = 0;
int secondDelim = 0;
for(int i=0; i<=tmp.Length(); i++)
{
if(IsDelimiter(" ", tmp, i));
{
if ( firstDelim == 0 )
firstDelim = i;
else
{
secondDelim = i;
break;
}
}
if ( secondDelim > 0 )
break;
}
int str_length = secondDelim - firstDelim;
ShowMessage(tmp.SubString(firstDelim, str_length));
Can someone give me a hint how to get this to work?

Not unless you give us a hint about the format of the string,
and what determines where you want to look to find the number.
Is my code way off, or is there a better way to do it?

Probably. Most of the time, for this sort of thing,
boost::regex is the simplest solution. Of course, once you've
got the numeric field, you'll have to use std::istringstream to
convert it.
 
R

Reetesh Mukul

From here:


to here. Is this block of code necessary?






Wouldn't this be a simpler way of doing the same thing?

int main()
{
std::string s = "dsdhjsahdk dsdjdsaj 36782367 sdjdhak";

int i = 0;
std::stringstream cstr( s );
char ch = 0;
while( cstr >> ch && !isdigit( ch ) )
{ }
cstr.putback( ch );
cstr >> i;
cout << i;

}

Yes, indeed.
 
R

Reetesh Mukul

Depending on how he is using the contents, it would be much more
efficient to assign the entire thing to the stringstream and keep
extracting int type until failbit it set. When it is set, clear it and
extract it to string type. Repeat until eof bit is set.

The solution you posted may not be useful if the OP actually wants to
do something with the non integers.. at least not efficient
It may also be error prone if the OP wants to extract strings that
contain numbers in them...Example: hello#1

Where as if he knows the text will be used for extracting either text
or ints, seperated by whitespace, than he can try to extract an int
and extract a string when int extraction fails. That we he is able to
use the entire contents in one swoop.

Of course, the OP didn't really give specifics.

Actually the specification is not there. Indeed, there can be problems
in using the code I have posted.
 
R

Reetesh Mukul

From here:


to here. Is this block of code necessary?






Wouldn't this be a simpler way of doing the same thing?

int main()
{
std::string s = "dsdhjsahdk dsdjdsaj 36782367 sdjdhak";

int i = 0;
std::stringstream cstr( s );
char ch = 0;
while( cstr >> ch && !isdigit( ch ) )
{ }
cstr.putback( ch );
cstr >> i;
cout << i;

}

Actually, I assumed that numeric-digits will appear surrounded by
space. This means some thing like {alphabet}*space {digits}+
space({alphabet}*space)*. Your code will extract digits in the
following conditions also:- djshdjshj14524 jdhdss

Regards,
Reetesh Mukul
 
R

Reetesh Mukul

From here:


to here. Is this block of code necessary?






Wouldn't this be a simpler way of doing the same thing?

int main()
{
std::string s = "dsdhjsahdk dsdjdsaj 36782367 sdjdhak";

int i = 0;
std::stringstream cstr( s );
char ch = 0;
while( cstr >> ch && !isdigit( ch ) )
{ }
cstr.putback( ch );
cstr >> i;
cout << i;

}

Actually, I assumed that numeric-digits will appear surrounded by
space. This means some thing like {alphabet}*space {digits}+
space({alphabet}*space)*. Your code will extract digits in the
following conditions also:- djshdjshj14524 jdhdss

Regards,
Reetesh Mukul
 
S

sparkydarky

Actually, I assumed that numeric-digits will appear surrounded by
space. This means some thing like {alphabet}*space {digits}+
space({alphabet}*space)*. Your code will extract digits in the
following conditions also:- djshdjshj14524 jdhdss

Regards,
Reetesh Mukul

The original code I posted is 'compilable' code in Borland Delphi
Studio. My assumptions were that the number would be surrounded by
spaces, and actually that the number would be after the first space.

AnsiString:
The AnsiString data type is used to hold sequences of characters.
Each character is an AnsiChar, guaranteed to be 8 bits in size.
An AnsiString can hold any number of characters, restricted only by
memory.
Unlike ShortStrings, AnsiStrings are pointer referenced variables.
Storage is allocated for an AnsiString only when needed. For example,
assigning the value of one AnsiString to another does not allocate
storage for a copy of the first string. Instead, the reference count
of the first string is incremented, and the second AnsiString set to
point to it.

I thought I knew C++ a little, but I realized that I don't because I
can barely follow what you guys posted. I tried to put some of the
code into Borland C++ Builder, but seems like Borland does not follow
the standards very well. Thanks for all your help. This will give me
really good base to work on and see if I can get it to work.
 
D

Daniel T.

sparkydarky said:
I thought I knew C++ a little, but I realized that I don't because I
can barely follow what you guys posted. I tried to put some of the
code into Borland C++ Builder, but seems like Borland does not follow
the standards very well. Thanks for all your help. This will give me
really good base to work on and see if I can get it to work.

How about if I add all of the assumed bits? Copy the code below exactly
as written and paste it in. See if it compiles.

=== begin code ===
#include <limits>
#include <sstream>
#include <stdexcept>
#include <string>

int extractNumber( const std::string& str )
{
using namespace std;
int result = 0;
stringstream ss( str );
while ( !( ss >> result ) ) {
if ( !ss.eof() ) {
ss.clear();
ss.ignore( numeric_limits<streamsize>::max(), ' ' );
}
else {
throw runtime_error( "no number" );
}
}
return result;
}

=== end code ===
 
D

Daniel T.

Reetesh Mukul said:
Actually, I assumed that numeric-digits will appear surrounded by
space. This means some thing like {alphabet}*space {digits}+
space({alphabet}*space)*. Your code will extract digits in the
following conditions also:- djshdjshj14524 jdhdss

I still don't see why you had to make the procedure so complex. Also
note, if presented with "5x 7", your code will extract the '5', not the
'7'.

Your code is emulated pretty well by the code below, which is far
simpler:

int main()
{
std::string s = "dsdhjsahdk dsdjdsaj 36782367 sdjdhak";

int result = 0;
std::stringstream cstr( s );
char ch = 0;
while ( cstr >> ch && !isdigit( ch ) )
cstr.ignore( numeric_limits<streamsize>::max(), ' ' );
cstr.putback( ch );
cstr >> result;
cout << result;
}
 
R

Reetesh Mukul

I still don't see why you had to make the procedure so complex. Also
note, if presented with "5x 7", your code will extract the '5', not the
'7'.

Your code is emulated pretty well by the code below, which is far
simpler:

int main()
{
std::string s = "dsdhjsahdk dsdjdsaj 36782367 sdjdhak";

int result = 0;
std::stringstream cstr( s );
char ch = 0;
while ( cstr >> ch && !isdigit( ch ) )
cstr.ignore( numeric_limits<streamsize>::max(), ' ' );
cstr.putback( ch );
cstr >> result;
cout << result;

}

Yes, this is a great solution. Very simple and compact solution.

Regards,
Reetesh Mukul
 
D

Daniel T.

James Kanze said:
It fails if the separator is a tab, rather than a space.

The code has lots of assumptions and it fails if any of them don't hold,
that's not the point.

The question I asked Reetesh was why he had such a complex solution when
the above solution, which is far simpler, does the exact same thing. I'm
guessing that it was because he didn't know about the 'ignore()'
member-function, and didn't know that the putback and op>> would do the
"right thing" if the stream failed.
 
R

Reetesh Mukul

The code has lots of assumptions and it fails if any of them don't hold,
that's not the point.

The question I asked Reetesh was why he had such a complex solution when
the above solution, which is far simpler, does the exact same thing. I'm
guessing that it was because he didn't know about the 'ignore()'
member-function, and didn't know that the putback and op>> would do the
"right thing" if the stream failed.

Yes, you are right Daniel. I indeed didn't knew about 'ignore()' and
putback,op's mechanism after things fail. Now an obvious question is
popping in my mind, will it not be good to have predicates( functors )
in ignore function (or similar functions) ?

Regards,
Reetesh Mukul
 
J

James Kanze

Yes and no. IMHO, the point is that this is generally not a
good way to parse input. The ignore function is not flexible
enough to be generally of much use other than for
resynchronizing the input after an error (and even then, only
with very simple formats).
Yes, you are right Daniel. I indeed didn't knew about
'ignore()' and putback,op's mechanism after things fail. Now
an obvious question is popping in my mind, will it not be good
to have predicates( functors ) in ignore function (or similar
functions) ?

Probably because that's not its role. But it's an interesting
suggestion---it should be possible to define a manipulator which
skips using a predicate. More useful, probably, would be a
manipulator which skips using a regular expression. This would
be far from trivial with extended regular expressions, like
Boost (which requires at least a forward iterator, since
backtracking is necessary), but wouldn't be too hard with my
regular expression class, which doesn't support any of the
extensions, but will work with input iterators.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,999
Messages
2,570,243
Members
46,838
Latest member
KandiceChi

Latest Threads

Top