8

My function must process strings that look like say hello y(5) or data |x(3)|, and I need to be able to extract the integer shown and store it into a separate int variable called address. However, some strings passing through will not have any integers, and for these the address must default to 0. When a string contains an integer, it will always be in between parentheses. I've attempted to use sscanf, but, being very new to sscanf, I'm encountering problems.. For some reason, the address always reads as 0. Here's my code:

void process(string info)
{
int address = 0; // set to 0 in case info contains no digits
sscanf(info.c_str(), "%d", address);
.
.
.
// remainder of code makes other function calls using the address, etc
}

Any ideas as to why the sscanf fails to find the integer in between parentheses? Thanks!

J. Shephard
  • 93
  • 1
  • 1
  • 6
  • 1
    `hello` doesn't match `%d` . You need to find a way to skip up to the beginning of your integer before applying `%d`. The `strchr` function could be one way. Also you forgot `&` before `address`. – M.M Nov 23 '15 at 05:06
  • Can't you use standard parsing techniques to construct some [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree) or embed some existing interpreter (like [Guile](http://www.gnu.org/software/guile/) or [Lua](http://lua.org/)...)? – Basile Starynkevitch Nov 23 '15 at 06:13

4 Answers4

9

why the sscanf fails to find the integer in between parentheses

The "%d" in sscanf(info.c_str(), "%d", address) will cause sscanf() to stop scanning once a non-numeric sequence detected. Text like "(5)" will simply stop scanning at the "(".

Instead code need to to skip over non-numeric text.


Pseudo-code

  in a loop
    search for any of "-+0123456789"
    if not found return 0
    convert from that point using sscanf() or strtol()
    if that succeeds, return number
    else advance to next character

Sample code

int address;
const char *p = info.c_str();
for (;;) {
  p += strcspn(p, "0123456789+-");
  if (*p == 0) return 0;
  if (sscanf(p, "%d", &address) == 1) {
    return address;
  }
  p++;
}

Notes:

The strcspn function computes the length of the maximum initial segment of the string pointed to by s1 which consists entirely of characters not from the string pointed to by s2. C11 7.24.5.3 2


If code wants to rely on " it will always be in between parentheses." and input like "abc()def(123)" does not occur which has preceding non-numeric data between ().:

const char *p = info.c_str();
int address;
if (sscanf(p, "%*[^(](%d", &address)==1) {
  return address;
}
return 0;

or simply

int address = 0;
sscanf(info.c_str(), "%*[^(](%d", &address);
return address;
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • +1 didn't saw the last edit. answer the same thing. anyway, what should be returned if the string is `data(5`. Your code seems like 5. even though not inside the parenthesis. – Shakil Ahamed Nov 23 '15 at 05:41
  • @silentboy The simplified code takes advantage of OP's "When a string contains an integer, it will always be in between parentheses." so `(5` does not occur. – chux - Reinstate Monica Nov 23 '15 at 05:44
2

You could use something as simple as this where strchr finds the first occurrence of "(" then use atoi to return the integer which will stop at the first non-digit.

  char s1[] = "hello y(5)";
  char s2[] = "data [x(3)]";
  char s3[] = "hello";

  int a1 = 0;
  int a2 = 0;
  int a3 = 0;

  char* tok = strchr( s1, '(');
  if (tok != NULL)
    a1 = atoi(tok+1);

  tok = strchr( s2, '(');
  if (tok != NULL)
    a2 = atoi(tok+1);

  tok = strchr(s3,'(');
  if (tok != NULL)
    a3 = atoi(tok+1);

  printf( "a1=%d, a2=%d, a3=%d", a1,a2,a3);

  return 0;
AndersK
  • 35,813
  • 6
  • 60
  • 86
2

When a string contains an integer, it will always be in between parentheses

To strictly conform with this requirement you can try:

void process(string info)
{
    int address;
    char c = '5'; //any value other than ) should work

    sscanf(info.c_str(), "%*[^(](%d%c", &address, &c);
    if(c != ')') address = 0;
    .
    .
    .
}
jxh
  • 69,070
  • 8
  • 110
  • 193
Shakil Ahamed
  • 587
  • 3
  • 18
0

link to a solution

int address;

sscanf(info.c_str(), "%*[^0-9]%d", &address);
printf("%d", address);

this should extract the integer between the parenthesis

William Ku
  • 798
  • 5
  • 17
  • 2
    note: this will fail if there are no characters before the integer, because `%[` must always match at least one character – M.M Nov 23 '15 at 05:01
  • 1
    the behaviour of `-` with `%[` is *implementation-defined* ; various compilers may or may not support this. (But you could use `^0123456789`). – M.M Nov 23 '15 at 05:01
  • This will convert "-123" into `123`. if will convert `"123"` into undefined value. – chux - Reinstate Monica Nov 23 '15 at 05:03