2015-06-21 89 views
0

所以我一直在工作的一个C++项目和IM停留在这个问题上,基本上林做节目,用户可以输入自己的名字,我以后再打印出来的文件时,用户的名字和姓氏用逗号分开,但逗号周围的可选空白是允许的。这就是我一直在使用的读取用户名:读可选白色空间(

char lastName[20]; 
    char firstName[20]; 
    char line[LINESIZE]; 
    while(fgets(line,LINESIZE,stdin)) { 
     if((sscanf(line," %s , %s ",lastName,firstName)) == 2) { 
      /*process name */ 
     } 
    } 

然而,它读取输入成功是唯一的一次,当用户输入:

john , doe 

其中%S,%S匹配我有,我怎么能使它像这样:

john, doe 
john ,doe 

都可以工作?

我也曾尝试

sscanf(line,"%s%[],%[]%s"); 

这不导致编译错误,但它不处理输入意味着它不匹配%S,%S

+1

你会发现这样更容易完成使用'strtok'。 – zwol

+2

@zwol:'sscanf'和朋友有很多quirls的,'strtok'在其自己的方式打破...只是解析手串。 – chqrlie

回答

1

,这样的"Doe , John"任何置换过滤掉空格这将隔离名

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

#define LINESIZE 100 

int main(void) { 
    char lastName[20] = {0}; 
    char firstName[20] = {0}; 
    char line[LINESIZE]; 
    char *first = NULL, *last = NULL; 
    if (NULL == fgets(line,LINESIZE,stdin)) 
     return 1; 
    last = strtok (line, ", \t\r\n"); 
    if (last) 
     first = strtok (NULL, ", \t\r\n"); 

    if (last && first) { 
     sprintf(firstName, "%.19s", first); 
     sprintf(lastName, "%.19s", last); 
     printf ("%s %s\n", firstName, lastName); 
    } 
    return 0; 
} 
+0

请不要鼓励使用'strncpy'。还要注意''strtok()'会跳过多个逗号,包括'line'的开头。这可能有点过于灵活。 – chqrlie

+0

@chqrlie我已经替换了'strncpy',它也不需要初始化'firstName'和'lastName'(因为当达到缓冲区大小时'strncpy'不会附加''\ 0'')。 –

+0

你应该使用'snprintf'来避免硬编码的'%.19s'。 'sprintf'也容易出错;-) – chqrlie

4

您可以修改sscanf格式使它执行更严格的测试:

char eol[2]; 
if (sscanf(line, " %19[a-zA-Z-] , %19[a-zA-Z-]%1[\n]", lastName, firstName, eol) == 3) ... 

sscanf将验证用户键入制成由逗号分隔的字母恰好2个词语和可选空格,然后换行。

但我强烈建议您解析输入自己而不是依靠sscanf。这并不难,更精确,灵活,且不易出错:

char lastName[LINESIZE]; 
char firstName[LINESIZE]; 
char line[LINESIZE]; 
while(fgets(line,LINESIZE,stdin)) { 
    char *p = line, *q; 
    while (isspace((unsigned char)*p)) p++; 
    for (q = lastName; isalpha((unsigned char)*p); p++) { 
     *q++ = *p; 
    } 
    *q = '\0'; 
    while (isspace((unsigned char)*p)) p++; 
    if (*p == ',') p++; 
    while (isspace((unsigned char)*p)) p++; 
    for (q = firstName; isalpha((unsigned char)*p); p++) { 
     *q++ = *p; 
    } 
    *q = '\0'; 
    while (isspace((unsigned char)*p)) p++; 
    if (*lastName && *firstName && !*p) { 
     // format is OK 
     printf("Hello %s %s\n", firstName, lastName); 
    } 
} 
+1

如果你知道你是有限的空间,就可以避免函数调用简单地用'读姓氏,而(* P!=“” || * P!=“”)',然后阅读'而(* P ==''|| * p ==',')'跳过空格和逗号,然后用'strcpy(firstname,p)'完成。 (如果你正在防范恶意名字,你也可以'strlen'和'strncpy')。 '和strchr(P, ' ')'也可以用于跳转到逗号和测试'如果(P - 1 =='')',然后从'line'设置临时'\ N'读取'lastName'等等。 –

+0

@大卫C.兰:谢谢你的建议,但第一个循环是不正确(''||代替''&&而不是测试'“\ 0''),第二将接受多个'”,''我认为这是不正确的,'strcpy'不会检查字母并接受多个单词。 'strncpy'是一个好主意,因为它违反直觉的语义来保护它免受恶意输入,跳到'',''''strchr'不会检查字母,而''''在它是可选的之前......我会支持一个内联函数可以跳过空格,另一个可以跳过字母。 – chqrlie

+0

我纠正':p'好,赶上。我同意你的评估,这就是为什么我在评论中把它作为一个注释掉落的原因。使用'strchr',因为你正在读取一个字符串,所以推测你会把它传递给'strtol',在那里解决任何非数字问题。我更喜欢将指针放在字符串的下面,如果您愿意,可以完全控制拒绝前面的字符。 –