如何使用sscanf读取带空格的字符串然后使用数字?

时间:2013-03-16 07:39:57

标签: c string scanf

我想从键盘数据中读取要插入的列表。 例如,如果我键入ins "name_to_insert" 19930412,则字符串name应为name_to_insert,不带引号,date应为19930412。 我不知道如何正确指定第二个sscanf。

char op[4], name[30], s[50];
int date;
while (scanf("%[^\n]%*c", s)==1)
{
    sscanf(s, "%s", op);
    if (strcmp(op, "ins")==0)
    {
        sscanf(s, "%*s %[^0-9]%d", name, &date);
        printf("Name is %s and date is %d\n", name, date);
    }
}

3 个答案:

答案 0 :(得分:1)

你几乎是对的。假设引号是必需的,您只需将扫描集转换说明符包装在引号中:

if (sscanf(s, "%*s \"%29[^\"]\" %d", name, &date) != 2)
    ...oops...

注意%29[^0-9];这将字符串限制为29个字节加上适合30字节数组的终端null '\0'。您也应该对外部scanf()进行类似的检查,或者只使用fgets()代替scanf()

如果引号是可选的,则必须稍微努力,将名称扫描为非数字并在扫描后删除引号:

if (sscanf(s, "%*s %29[^0-9] %d", name, &date) != 2)
    ...oops...

这是一些测试代码:

#include <stdio.h>

static void scanner(const char *fmt, const char *s)
{
    char name[30];
    int  date;

    if (sscanf(s, fmt, name, &date) != 2)
        printf("Scan failed {%s} and {%s}\n", fmt, s);
    else
        printf("{%s} and {%s} => {%s} %d\n", fmt, s, name, date);
}

int main(void)
{
    char source[][30] =
    {
        "ins \"name in quotes\" 12345",
        "ins name without quotes 12345",
    };
    enum { NUM_SOURCE = sizeof(source) / sizeof(source[0]) };
    char format[][20] =
    {
        "%*s \"%29[^\"]\" %d",
        "%*s %29[^0-9] %d",
    };
    enum { NUM_FORMAT = sizeof(format) / sizeof(format[0]) };

    for (int i = 0; i < NUM_FORMAT; i++)
    {
        for (int j = 0; j < NUM_SOURCE; j++)
            scanner(format[i], source[j]);
    }
    return 0;
}

示例输出:

{%*s "%29[^"]" %d} and {ins "name in quotes" 12345} => {name in quotes} 12345
Scan failed {%*s "%29[^"]" %d} and {ins name without quotes 12345}
{%*s %29[^0-9] %d} and {ins "name in quotes" 12345} => {"name in quotes" } 12345
{%*s %29[^0-9] %d} and {ins name without quotes 12345} => {name without quotes } 12345

预计转换失败;格式查找引号,但没有。

我还使用稍微不同的线束和格式字符串:

"%*s %1[\"]%29[^\"]%1[\"] %d"

(传递两个2个字符的字符串,q1q2来保存引号),但是当引号丢失时,扫描失败;报价不是可选的。

请注意,名称具有尾随空格,而引号具有第二种格式;那些必须单独删除。

答案 1 :(得分:1)

我通过简单地删除名称中的第一个和最后一个字符解决了引号的问题:

char op[4], nameTemp[30], *name, s[50];
int date;
while (scanf("%[^\n]%*c", s)==1)
{
    sscanf(s, "%s", op);
    if (strcmp(op, "ins")==0)
    {
        sscanf(s, "%*s %[^0-9]%d", nameTemp, &date);
        name=nameTemp+1;
        name[strlen(name)-2]='\0';
        printf("Name is %s and date is %d\n", name, date);
    }
}

答案 2 :(得分:0)

sscanf(s, "%*s \"%[^\"]\" %d", name, &date);