2015-06-21 90 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',在那裏解決任何非數字問題。我更喜歡將指針放在字符串的下面,如果您願意,可以完全控制拒絕前面的字符。 –