0

I'm reading a string that has two numbers with an arithmetic operator between them, like one of these:

A1 + B1
A1 - B1
A1 * B1
A1 / B1

I can read A1 and B1 but not the operator. I'm reading using this:

while (sscanf(matrix[i][c] + offset, "%c%d%*c%n",
       &col, &line, &readCharCount) == 2) {
  // do something
}

What can I do to read the operator?

Adam Liss
  • 47,594
  • 12
  • 108
  • 150
GoldenMedal
  • 102
  • 2
  • 9
  • 2
    It's called a "sign". (Even better, a "character", but I guess that would be too high an expectation.) –  Jun 22 '13 at 03:01
  • @H2CO3 I think he meant sigil – xaxxon Jun 22 '13 at 03:18
  • 1
    possible duplicate of [replacing pieces of string](http://stackoverflow.com/questions/17241897/replacing-pieces-of-string) – Lion Jun 22 '13 at 03:22
  • @Lion: same OP, similar scenario, but I think it is a different question. The other one is asking about how to replace the data in the string, but that more or less presupposes that this parsing has been done. It isn't clear-cut, but I think they're different. – Jonathan Leffler Jun 22 '13 at 04:04

4 Answers4

4

Unlike the numeric conversion specifiers and %s, the %c conversion specifier does not skip blanks. Thus, given your example inputs, the %*c is reading the blank before the operator. You could sensibly use:

while (sscanf(matrix[i][c] + offset, " %c%d %c %c%d", &col1, &row1, &op, &col2, &row2) == 5)
    ...data is OK...

Since you're using an offset and were capturing where the scan ended, you would use:

while (sscanf(matrix[i][c] + offset, " %c%d %c %c%d%n",
              &col1, &row1, &op, &col2, &row2, &readCharCount) == 5)
    ...data is OK...

Note that the %n conversion specifier is not counted, so the test remains against 5, not 6.

Also note the careful placement of spaces in the format string. They're necessary and flexible (that would handle A1+B2 OK, as well as A1 + B2). If you are going to allow bigger spreadsheets, you might prefer to specify:

while (sscanf(matrix[i][c] + offset, " %4[a-zA-Z]%d %c %4[a-zA-Z]%d%n",
              col1, &row1, &op, col2, &row2, &readCharCount) == 5)
    ...data is OK...

where the type of col1 and col2 changes from a single to char col1[5]; char col2[5]; (which is why the & was dropped, too). The scan sets allow inputs like aAa1 + BbB2 to be recognized. Because of the %d notation, spaces are allowed between the letter or letters and the number (so the code would allow aaa 999 + bbb 888. Avoiding that is hard; I think you'd need to process the data with two scansets:

while (sscanf(matrix[i][c] + offset, " %4[a-zA-Z]%5[0-9] %c %4[a-zA-Z]%5[0-9]%n",
              col1, row1, &op, col2, row2, &readCharCount) == 5)
    ...data is OK...

where the types are now char row1[6]; char row2[6]; and the ampersands have been dropped again. You can then confidently convert row1 and row2 into numbers.

See also: Calc cell convertor in C for code to convert column numbers into the corresponding alphabetic codes.

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • i tried the last example and it became a infinity loop. i will have more than 2 "pairs" of row and col, can i put this to became automatically? while (sscanf(matris[i][c] + offset, " %4[a-zA-Z]%5[0-9] %c %4[a-zA-Z]%5[0-9]%n", col1, row1, &op, col2, row2, &readCharCount) == 5){ printf("Col: %s, LIne: %s, OP: %c\n", col1, row1, op); printf("Col: %s, LIne: %s, OP: %c\n", col2, row2, op); } thanks – GoldenMedal Jun 22 '13 at 15:02
  • You would have to add `readCharCount` to `offset` to resume reading where the first call left off; that would be in the `...data is OK...` loop body. Otherwise, you keep reading the same part of the string over and over again, which is indeed an infinite loop. – Jonathan Leffler Jun 23 '13 at 01:03
  • i tryied http://pastebin.com/LM8326Gz and input A1+C2+D3+B3 and my result was: A1, C2, + => ONLY. what i did wrong? – GoldenMedal Jun 23 '13 at 17:01
  • You said you had terms like `A1+B1` and `C2/D3` but didn't mention connecting those terms with `+` signs. The format expression I gave works precisely on `V1*V2`; it doesn't read the `+` separating that from `V3-V4`. (You didn't mention that you'd need it to, so I had no way of knowing that you'd need it to do that — a lesson in the problems that incomplete and vague specifications lead to.) It sounds like you need a general purpose lexical scanner, and you don't write that using `sscanf()` unless you're desparate. You write a scanner function that reads data and identifies what it just read. – Jonathan Leffler Jun 23 '13 at 18:55
1

If I understand the problem, you're reading two numbers with a single character between them. So you'd read each number into an int using the format string %d, and you'd read the character into a string (char[] array) using the format string %s:

int nFirst;
int nSecond;
char op[5];  // operator, null, and some extra space to avoid overflow.

while (sscanf(matrix[i][c] + offset, "%d %s %d",
       &nFirst, op, &nSecond) == 3)

Note that you must pass the address of the int variables, but the name of the char[] array already resolves to an address.

The return value of sscanf should be 3, because returns the number of items converted, and you expect it to fill 3 variables.

Adam Liss
  • 47,594
  • 12
  • 108
  • 150
0

When You give "%*c", It means read one character and ignore that. So, You are ignoring the sign in the format string. I think it is working as designed. You may need to do something like this.

char col, sign;
int line, readCharCount;

sscanf (matris[i][c] + offset, "%c%d%c%n", &col, &line, &sign, &readCharCount);

/* Read count and return value will be 3 */

A1+ will be Read this.

col = 'A';
line = 1;
sign = '+'
readCharCount = 3;

Is this what You are looking for?

You changed the Original post. Let me add something for the new requirement!

char a1[5], b1[5], sign;
int readCharCount;

sscanf (matris[i][c] + offset, "%s %c %s%n", a1, &sign, b1, &readCharCount);

/* Read count and return value will be 3 */

"A1 + B1" will be Read like this.

a1 = "A1";  // String
sign = '+'  // Character
b1 = "B1";  // String
readCharCount = 3;  // No of items read. Return value will also be 3.

The New Input Stream is: A1+B1+C1+D1+E2-F3*G1

Here is the code to read, assuming the stream is terminated with '\n' :

char c1, c2, c3;

c1 = '\0';
while (c1 != '\n')
{
     scanf("%c%c%c", &c1, &c2, &c3);
     if(c1 != '\n')
     {
          /* Process characters */
     }
}
sukumarst
  • 265
  • 1
  • 5
  • This is different format of input Stream. You need to give all of your formats for giving a correct way of scanning it. So, define all possible formats of your input Stream first here... – sukumarst Jun 22 '13 at 14:18
  • so, i use while and take from 3 groups? while(sscanf(matris[i][c] + offset, "%s %c%n", and here i would take this %s dinamically at each pass... – GoldenMedal Jun 22 '13 at 18:11
0

I believe Adam's post is correct, but it will encounter problems if there is no space between the + and the operand number that follows it.

With "%d%s%d", the string "1234 +5555" will cause the %s to catch +5555.

I made the following program, and this catches the operands correctly regardless of the existence of spaces. However, the variable string may contain a string with white-spaces. Note that [^0123456789 ] means "match all characters that are not numbers".

int main (int argc, char ** argv) {
    int a, b;
    char string[100];
    scanf ("%d%[^0123456789 ]%d", &a, string, &b);

    printf ("a = %d\n", a);
    printf ("str = %s\n", string);
    printf ("b = %d\n", b);
}

I hope this helps!

ComputerNerd
  • 63
  • 10