简体   繁体   English

C sscanf 验证输入格式

[英]C sscanf to validate input format

I want to write a program which reads a line of input from the user, in the following format: <Name>,<Age>,<City>我想编写一个程序,它从用户那里读取一行输入,格式如下: <Name>,<Age>,<City>

  • The Name can contain English letters, spaces and - only.名称只能包含英文字母、空格和-
  • The Age must be an integer between 18 to 120.年龄必须是介于 18 到 120 之间的 integer。
  • The City must contain English letters and - only. City 必须包含英文字母和- only。

Each of them can be of size 49. I want to store the information and print an informative error will be printed for bad input.它们中的每一个都可以是 49 号。我想存储信息并打印一个信息性错误将打印错误输入。

My code is the following:我的代码如下:

    char str[150];
    char input[3][50] = { 0 };
    int num = 0;
    if (fgets(str, 150, stdin) != NULL) {
        num = sscanf(str, "%[a-zA-Z -],%[0-9],%[a-zA-Z-]", input[0], input[1], input[2]);
    }
    if (num < 3) {
        printf("ERROR\n");
    }

The problem is that an error will not be printed for an input such as Name1$#,20,NY , Best,19,Rome123 , or Best,100,Paris1$ , where the city is in wrong format (with trailing characters).问题是对于诸如Name1$#,20,NYBest,19,Rome123Best,100,Paris1$之类的输入不会打印错误,其中城市格式错误(带有尾随字符)。 There is any way to solve it using sscanf ?有什么方法可以使用sscanf解决它?

You can use sscanf() and character classes for your purpose but there are small problems with your format string:您可以根据需要使用sscanf()和字符类,但格式字符串存在一些小问题:

  • AZ assumes ASCII encoding or at least an encoding where letters are contiguous. AZ采用 ASCII 编码或至少是字母连续的编码。
  • a trailing - has a special meaning, put the dash in first position to match a dash explicitly.尾随-具有特殊含义,将破折号放在第一个 position 以明确匹配破折号。
  • there is no length prefix, so a name or city longer than 49 characters will overflow the destination array.没有长度前缀,因此超过 49 个字符的名称或城市将溢出目标数组。

Rather than using fgets() , you should read the line mannually to detect overlong lines.而不是使用fgets() ,您应该手动阅读该行以检测过长的行。

You can add an extra %c to check for extra characters at the end of the line.您可以添加额外的%c以检查行尾的额外字符。 Storing the converted value is not required if you don't intend to use the field values, but you must convert the number to check if its value is in the requested range:如果您不打算使用字段值,则不需要存储转换后的值,但您必须转换数字以检查其值是否在请求的范围内:

    char str[150];
    char name[50];
    char city[50];
    char agestr[4];
    size_t i;
    int c, age, pos, n;

    for (i = 0; (c = getchar()) != EOF && c != '\n'; i++) {
        if (i < sizeof(str) - 1)
            str[i] = (char)c;
    }
    if (c == EOF && i == 0) {
        printf("end of file\n");
        return -1;
    }
    if (i >= sizeof(str)) {
        printf("line too long\n");
        return 0;
    }
    str[i] = '\0';
    pos = 0;
    /* validate the name */
    if (sscanf(str + pos, "%49[-a-zA-Z ]%n", name, &n) != 1 || str[pos + n] != ',') {
        printf("invalid name\n");
        return 0;
    }
    pos += n + 1;
    /* validate the age */
    if (str[pos] == '0' || sscanf(str + pos, "%3[0-9]%n", agestr, &n) != 1 || str[pos + n] != ',') {
        printf("invalid age\n");
        return 0;
    }
    age = atoi(agestr);
    if (age < 18 || age > 120) {
        printf("age out of range: %d\n", age);
        return 0;
    }
    pos += n + 1;
    /* validate the city */
    if (sscanf(str + pos, "%49[-a-zA-Z]%n", city, &n) != 1 || str[pos + n] != '\0') {
        printf("invalid city\n");
        return 0;
    }
    /* Input was validated... proceed */

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

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