views:

63

answers:

6

Hi there, given a string say " a 19 b c d 20", how do I test to see if at that particular position on the string there is a number? (not just the character '1' but the whole number '19' and '20').

char s[80];
strcpy(s,"a 19 b c d 20");

int i=0;
int num=0;
int digit=0;
for (i =0;i<strlen(s);i++){
    if ((s[i] <= '9') && (s[i] >= '0')){    //how do i test for the whole integer value not just a digit

        //if number then convert to integer
        digit = s[i]-48;
        num = num*10+digit;
    }

    if (s[i] == ' '){
        break; //is this correct here? do nothing
    }
    if (s[i] == 'a'){
       //copy into a temp char
    }
}
A: 

You can use atoi().

Max Shawabkeh
The page you reference says "The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function." So it sounds like "abc123" will not be converted to 123.
Mawg
Indeed they won't. The question however specifies that he's looking for a number "at that particular position".
Max Shawabkeh
A: 

after your if you need to shift to while to collect subqsequent digits until you hit a non-digit.

BUT, more inportantly, have you clearly defined your requirements? Will you allow whitespace between the digits? What if there are two numbers, like abc123def456gh?

Mawg
A: 

There's no way to test for a whole number. Writing a lexer, as you've done is one way to go. Another would be to try and use the C standard library's strtoul function (or some similar function depending on whether the string has floating point numbers etc).

Your code needs to allow for whitespaces and you can use the C library's isdigit to test if the current character is a digit or not:

vector<int> parse(string const& s) {
     vector<int> vi;
     for (size_t i = 0; i < s.length();) {
         while (::isspace((unsigned char)s[ i ]) i++;
         if (::isdigit((unsigned char)s[ i ])) {
              int num = s[ i ] - '0';
              while (::isdigit((unsigned char)s[ i ])) {
                 num = num * 10 + (s[ i ] - '0');
                 ++i;
              }
              vi.push_back(num);
         }
                ....

Another approach will be to use boost::lexical_cast:

 vector<string> tokenize(string const& input) {
     vector<string> tokens;
     size_t off = 0, start = 0;
     while ((off = input.find(' ', start)) != string::npos) {
          tokens.push_back(input.substr(start, off-start));
          start = off + 1;
     }
     return tokens;
 }

 vector<int> getint(vector<string> tokens) {
      vector<int> vi;
      for (vector<string> b = tokens.begin(), e = tokens.end(); b! = e; ++b) {
         try
         {
           tokens.push_back(lexical_cast<short>(*b));
         }
         catch(bad_lexical_cast &) {}
      }
      return vi;
 }
dirkgently
+4  A: 

These are C solutions:

Are you just trying to parse the numbers out of the string? Then you can just walk the string using strtol().

long num = 0;
char *endptr = NULL;
while (*s) {
  num = strtol(s, &endptr, 10);
  if (endptr == s) { // Not a number here, move on.
    s++;
    continue;
  }
  // Found a number and it is in num. Move to next location.
  s = endptr;
  // Do something with num.
}

If you have a specific location and number to check for you can still do something similar.
For example: Is '19' at position 10?

int pos = 10;
int value = 19;
if (pos >= strlen(s))
  return false;
if (value == strtol(s + pos, &endptr, 10) && endptr != s + pos)
  return true;
return false;

Are you trying to parse out the numbers without using any library routines?

Note: I haven't tested this...

int num=0;
int sign=1;
while (*s) {
  // This could be done with an if, too.
  switch (*s) {
    case '-':
      sign = -1;
    case '+':
      s++;
      if (*s < '0' || *s > '9') {
        sign = 1;
        break;
      }
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      // Parse number, start with zero.
      num = 0;
      do {
        num = (num * 10) + (*s - '0');
        s++;
      } while (*s >= '0' && *s <= '9');
      num *= sign;
      // Restore sign, just in case
      sign = 1;
      // Do something with num.
      break;
    default:
      // Not a number
      s++;
  }
}
Harvey
A: 

Its not very clear what you are looking for.. Assuming you want to extract all the digits from a string and then from a whole number from the found digits you can try the following:

    int i;
    unsigned long num=0; // to hold the whole number.
    int digit;
    for (i =0;i<s[i];i++){
            // see if the ith char is a digit..if yes extract consecutive digits
            while(isdigit(s[i])) { 
                    num = num * 10 + (s[i] - '0');
                    i++;
            }
    }

It is assumed that all the digits in your string when concatenated to from the whole number will not overflow the long data type.

codaddict
A: 

It seems like you want to parse the string and extract all the numbers from it; if so, here's a more "C++" way to do it:

string s = "a 19 b c d 20"; // your char array will work fine here too
istringstream buffer(s);
string token;
int num;
while (!buffer.eof())
{
    buffer >> num; // Try to read a number
    if (!buffer.fail()) {    // if it doesn't work, failbit is set
        cout << num << endl; // It's a number, do what you want here
    } else {
        buffer.clear();  // wasn't a number, clear the failbit
        buffer >> token; // pull out the non-numeric token
    }
}

This should print out the following:

19 
20

The stream extraction operator pulls out space-delimited tokens automatically, so you're saved from having to do any messy character-level operations or manual integer conversion. You'll need to #include <sstream> for the stringstream class.

tzaman