2

I'm triying to read a string with a specific format in C using scanf() The string has the format:

<LET,LET,LET> op

where LET is a capital letter and op has to be '+' or '%'.

These are valid entries:

<A,B,C> +
<A,W,Z> %
<Q,   X,W>    +

These are not:

<A,b,C> +
<A,W,Zddddd> %
<Q,X,W> *

I'm trying something like this

#include <stdio.h>

int ret = 0;
char str[8];
ret = scanf("%8[^\n]",str);

but str ends up with garbage. I just don't know how to read it and how to get only capital letters.

Thanks

5
  • What do you expect to be read into str? Commented Apr 27, 2016 at 4:33
  • Sorry.A string has the format: <LET,LET,LET> op where LET is a capital letter and op has to be '+' or '%'. Commented Apr 27, 2016 at 4:40
  • Your example has + and * as op, and all three are numbers in the bracket. Commented Apr 27, 2016 at 4:42
  • I fixed it. LET is a capital letter and op has to be + or % Commented Apr 27, 2016 at 4:44
  • Should "<A,W,Zddddd> % qwerty" work or fail? Commented Apr 27, 2016 at 21:57

3 Answers 3

4

try this:

#include <stdio.h>

int main(void) {
    char let1[2], let2[2], let3[2], op[2];
    char line[80];
    while(fgets(line, sizeof line, stdin)){
        if(sscanf(line, "<%1[A-Z], %1[A-Z], %1[A-Z]> %1[+%]", let1, let2, let3, op) == 4)
            puts("valid");
        else
            puts("invalid");
    }

    return 0;
} 
Sign up to request clarification or add additional context in comments.

5 Comments

Why line is [80] and why each let is [2]?
[80] is my console's size of width. Please change to your required size.(However, in 8 it is small) [2] : one character + null-terminator.
This works great. But it doesnt work if I ad a space BEFORE a comma. Should I add a space after the comma on each %1[A-Z], ?
If the compiler does not allow A-Z, replace it with ABCDEFGHIJKLMNOPQRSTUVWXYZ.
@Telefang Try adding a space before and after the comma. (E.g %1[A-Z] , %1[A-Z]) It seems to work for me.
1

This method also detects trail garbage on the line.

"%n" saves the offset of the current scan. Only if n is non-zero and indexes '\0' was there success.

By using string literal concatenation, code can clearly show what format is being used for the various parts of the scan.

#include <stdio.h>

#define F_LET " %1[A-Z]"
#define F_SEP " ,"
#define F_OP  " %1[+%]"

int main(void) {
  char buf[100];
  while (fgets(buf, sizeof buf, stdin)) {
    char let[3][2];
    char op[2];
    int n = 0;
    sscanf(buf, " <" F_LET F_SEP F_LET F_SEP F_LET " >" F_OP " %n", 
        let[0], let[1], let[2], op, &n);

    puts((n && buf[n] == '\0') ? "Success" : "Fail");
  }
}

Comments

0

An alternative to BLUEPIXY's perfectly good answer, is to simply use char, and scan the input using %c instead, e.g.:

#include <stdio.h>
#include <ctype.h>

int main()
{
    char let1, let2, let3, op;
    char line[80]; // or some other suitable size

    while (fgets(line, sizeof line, stdin))
    {
        if (sscanf(line, "< %c , %c , %c > %c", &let1, &let2, &let3, &op) == 4 && (op == '+' || op == '%') && isupper(let1) && isupper(let2) && isupper(let3))
        {
            printf("valid!\nlet1 = %c\nlet2 = %c\nlet3 = %c\nop = %c\n", let1, let2, let3, op);
        }
        else
        {
            puts("invalid");
        }
    }
}

Note that the spaces before and after the %c are important as they allow sscanf to gobble up all whitespace before trying to match the %c or the comma.

Unlike BLUEPIXY's answer however, we have to check that op matches + or % manually.

EDIT: I missed the part where the LET characters must be uppercase. I've fixed the answer, but of course, it is now more complicated.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.