简体   繁体   English

如何测试 C 中的输入字符串是否具有正确的“格式”?

[英]How to test that an input string in C is of the correct 'format'?

I've written a simple calculator app in C and it works pretty well so far but I'm missing one thing: how to ensure the user has entered an input in the correct form eg "6 + 7".我已经用 C 编写了一个简单的计算器应用程序,到目前为止它运行良好,但我遗漏了一件事:如何确保用户以正确的形式输入了一个输入,例如“6 + 7”。 Is there any way I can test for that?有什么办法可以测试吗?

Here is my code so far:到目前为止,这是我的代码:

/*A simple calculator that can add, subtract and multiple. TODO: Division
and add error handling i.e. if not an expected input!*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
  char input[10];
  int result;
  printf("Welcome to the calculator! The available operations are +, - and *.\n");
  while (1) {
    printf("What would you like to calculate?\n");
    fgets(input, 10, stdin); /*Getting user input in form e.g. 4 + 7*/

    /*Ideally test for input should go here*/

    /*Separating user input into the numbers and operators, using strtok and
    space as a delimiter*/
    char *firstNumber = strtok(input, " ");
    char *operator = strtok(NULL, " ");
    char *secondNumber = strtok(NULL, " ");

    /*Converting the separated numbers to integers*/
    int firstInt = atoi(firstNumber);
    int secondInt = atoi(secondNumber);

    if (strcmp(operator, "+") == 0) {
      result = firstInt + secondInt;
    } else if (strcmp(operator, "-") == 0) {
      result = firstInt - secondInt;
    } else if (strcmp(operator, "*") == 0) {
      result = firstInt * secondInt;
    } else {
      printf("That ain't a valid operator sonny jim. Try again:\n");
      continue;
    }

    printf("Your result is %d.\n", result);

    int flag = 0;

    while (flag == 0) {
      printf("Would you like to do another calculation? (yes or no)\n");
      fgets(input, 10, stdin);
      if (strcmp(input, "yes\n") == 0) {
        flag = 1;
      } else if (strcmp(input, "no\n") == 0) {
        flag = 2;
      } else {
        printf("That isn't a valid response. Please respond yes or no.\n");
      }
    }
    if (flag == 2) {
      break;
    }
  }

  return 0;

}

Not necessarily the best way, but I would use sscanf this way:不一定是最好的方法,但我会这样使用sscanf

    int firstInt;
    int secondInt;
    char operator;
    if (3 != sscanf(input, "%d %c %d %1[^\n]", &firstInt, &operator, &secondInt, &temp)) {
      printf("Invalid input Billy!\n");
      continue;
    }

sscanf should return 3 if it successfully read in the values from the input string.如果sscanf成功读取输入字符串中的值,则应返回 3。 If it would return 4 that would mean it read some trailing non whitespace characters which is invalid.如果它将返回 4,则意味着它读取了一些无效的尾随非空白字符。 The added benefit of this approach is that you don't need to parse the operands elsewhere with atoi .这种方法的额外好处是您不需要使用atoi解析其他地方的操作数。

Whole code:全码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
  char input[10];
  char temp[2];
  int result;
  printf("Welcome to the calculator! The available operations are +, - and *.\n");
  while (1) {
    printf("What would you like to calculate?\n");
    fgets(input, 10, stdin); /*Getting user input in form e.g. 4 + 7*/

    /*Ideally test for input should go here*/
    int firstInt;
    int secondInt;
    char operator;
    if (3 != sscanf(input, "%d %c %d %1[^\n]", &firstInt, &operator, &secondInt, temp)) {
      printf("Invalid input Billy!\n");
      continue;
    }

    if ('+'== operator) {
      result = firstInt + secondInt;
    } else if ('-' == operator) {
      result = firstInt - secondInt;
    } else if ('*' == operator) {
      result = firstInt * secondInt;
    } else {
      printf("That ain't a valid operator sonny jim. Try again:\n");
      continue;
    }

    printf("Your result is %d.\n", result);

    int flag = 0;

    while (flag == 0) {
      printf("Would you like to do another calculation? (yes or no)\n");
      fgets(input, 10, stdin);
      if (strcmp(input, "yes\n") == 0) {
        flag = 1;
      } else if (strcmp(input, "no\n") == 0) {
        flag = 2;
      } else {
        printf("That isn't a valid response. Please respond yes or no.\n");
      }
    }
    if (flag == 2) {
      break;
    }
  }
  return 0;
}

The first test you should do is for length.您应该做的第一个测试是长度。 You only allow input of ten characters.您只允许输入十个字符。 That's one for the operator, two for spaces, one for the \\n , and one for the NUL terminator.一个用于运算符,两个用于空格,一个用于\\n ,一个用于NUL终止符。 That leaves only 5 characters to be split amongst the two operands.这样就只剩下 5 个字符要在两个操作数之间拆分了。 So, if the user inputs 543 * 65 , you've already truncated the \\n .因此,如果用户输入543 * 65 ,则您已经截断了\\n An input of 5432 * 65 , and you start losing important data.输入5432 * 65 ,您开始丢失重要数据。 The way I would implement a length check is to search for the \\n :我实现长度检查的方法是搜索\\n
if (input[0] && input[strlen(input) - 1] != '\\n') , you know the input has been truncated. if (input[0] && input[strlen(input) - 1] != '\\n') ,您知道输入已被截断。 Next, you need to check for the validity of the characters. 接下来,您需要检查字符的有效性。 If you keep your strtok() method, you can do input checking when you convert the string to an integer if you use the preferred function strtol() †† with far better error checking.如果你保留你的strtok()方法,你可以在将字符串转换为整数时进行输入检查,如果你使用首选函数strtol() ††和更好的错误检查。 As for the operator, you already have checks on that.至于运营商,您已经对此进行了检查。 For formatting of input: check for NULL pointers .对于输入格式:检查 NULL 指针 If strtok() doesn't find a space delimiter, it will return a NULL pointer, which you would then try to read from later in your program.如果strtok()找不到空格分隔符,它将返回一个 NULL 指针,然后您将尝试在程序中稍后读取该指针。

†: I personally would make my input character limit larger: at least 25 †:我个人会让我的输入字符限制更大:至少 25
††: man strtol for more information ††: man strtol了解更多信息

string in C is of the correct 'format'? C 中的字符串是正确的“格式”吗?

A simpler approach uses " %n" at the end to record the offset of the scan - if it made it that far.一个更简单的方法是在末尾使用" %n"来记录扫描的偏移量——如果它已经做到了那么远。 Akin to @Chris Dodd comment.类似于@Chris Dodd评论。

int firstNumber;
char operator[2];
int secondNumber;

int n = 0;
sscanf(input, "%d %1[+-] %d %n", &firstNumber, operator, &secondNumber, &n);
//  v---v--------------------  Scan complete?
if (n > 0 && input[n] == '\0') Success();
//           ^--------------^  No extra junk at the end?
else Fail();

Detecting if a space exists is tricky.检测空间是否存在很棘手。 This answer and "%d %c %d" would pass `"5-7".这个答案和"%d %c %d"会通过“5-7”。 If spaces are required about the operator, use如果操作符需要空格,请使用

"%d%*[ ]%1[+-]*[ ]%d %n"

Notice the " " in " %n" allows scanning to be tolerant of a trailing '\\n' .请注意, " %n" " "中的" %n"允许扫描容忍尾随'\\n' Use as desired.根据需要使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM