2011-12-29 82 views
4

在我的程序中,我使用sscanf來檢查字符串是否具有給定的格式。爲此,我提供了格式字符串中的參數個數,並在分析輸入時檢查sscanf是否返回相同的數字。sscanf - 不同數量的格式參數?

作爲原語解析器的一部分,我想檢查一個字符串是否與許多格式之一匹配。 sscanf函數是可變的,所以我該如何處理需要傳遞的不同數量的參數?

目前,我只是將大量的參數(例如50)傳遞給該函數,並且希望格式化字符串不包含更多參數。

有沒有更好的方法來做到這一點?

+0

正則表達式可能會有幫助。 – Hogan 2011-12-29 21:23:35

+0

@Hogan:Afaik正則表達式不是C標準庫的一部分。 – ryyst 2011-12-29 21:26:12

+1

@ryyst他們不是標準的c,但他們是POSIX – Dave 2011-12-29 21:27:40

回答

3

您確實需要比scanf更重的東西。你必須告訴scanf你輸入的格式是什麼;它無法自行解決任何問題。

如果你有權訪問POSIX,看看regex.h這可能是你需要的一切。

否則,你卡在自己的身上。 lexyacc很好,如果格式比較複雜的話,或者strtok或者(getchar + switch)可能是要走的路。

編輯: 既然你可以使用POSIX,下面是一個簡單的例子,說明如何從c中的正則表達式提取數據。 (檢查排除錯誤簡潔。)

char txt[] = "232343341235898dfsfgs/.f"; 
regex_t reg; 
regmatch_t refs[MAX_REFS]; //as in, the maximum number of data you want to extract 
regcomp(&reg, "3433\\([0-5]*\\).*", 0); //replace 0 with REG_EXTENDED if desired 
regexec(&reg, txt, MAX_REFS, refs, 0); 
regfree(&reg); 

txt[refs[0].rm_eo+1] = '\0'; 
int n = atoi(txt+refs[0].rm_so); 
printf("%d\n", n); 

打印

41235 
+0

我有權訪問POSIX,所以'regex.h'將是我的下一個選擇。我可以用'regex.h'解析輸入到不同的變量,就像'sscanf'一樣,或者我必須同時使用'regex.h'和'sscanf'? – ryyst 2011-12-29 21:40:32

+0

所有你需要的是'regexec'。我會添加一個例子 – Dave 2011-12-29 21:42:58

0

您應該使用lex/yacc來構建適當的解析器。或者,首先使用strtok標記字符串可能會簡化您的問題。 (注意:正確使用strtok非常棘手 - 仔細閱讀其文檔。)

0

我不知道它回答你的問題,但you use varargs in C允許可變數量的參數的函數。

void myscanf(const char *fmt, ...) 
{ 
} 
0

無益的答案是「不這樣做,正確地寫一個解析器,也許使用lex和/或yaccbison」。

你問的問題的答案是「是的,你可以做到這一點」。我不相信有什麼理由可以讓更多的可變參數比格式要求,儘管很少會是一件壞事。我假設你有一個數組或可能的格式列表,並且你正在循環中調用sscanf。

0

您可以使用可變長度參數使用stdarg.h中提供的宏編寫驗證函數。

例如,

int my_validation_func(const char *format, ...) { 
    va_list ap; 
    char *p, *sval; 
    int ival; 
    float fval; 

    va_start(ap, format); 
    for(p=format; *p ; p++) { 
     if (*p != '%') { 
      continue; 
     } 
     switch(*++p) { 
      case 'd': 
       ival = va_arg(ap, int); 
       break; 

      case 'f': 
       fval = va_arg(ap, float); 
       break; 

      case 's': 
       for (sval = va_arg(ap, char *); *sval; sval++); 
       break; 

      default: 
       break; 
     } 
    } 
    va_end(ap); 
} 

希望這有助於!

0

如果你不知道當你寫代碼參數的數量和類型,sscanf()不能安全地做你想做的事情。

將50個參數傳遞給sscanf()是可以的(格式字符串不消耗的參數會被求值,但會被忽略),但對應于格式字符串的參數在提升後必須是預期的類型;否則,行爲是不確定的。因此,如果您想要檢測是否可以使用"%d""%f"掃描字符串,則無法通過單個sscanf()調用安全地執行此操作。 (很可能,你可以逃脫傳遞void*指向一個足夠大的緩衝區,但行爲仍是不確定的。)

另一個討厭的問題sscanf()的是,它不處理數字溢出。這:

char *s = "9999999999999999999999999"; 
int n; 
int result = sscanf(s, "%d", &n); 
printf("result = %d, n = %d\n", result, n); 

是未定義行爲(假設9999999999999999999999999是太大而不能存儲在int)。

你的東西可能能夠做的就是找到一個開源sscanf實施和修改它,它只是驗證對格式字符串,沒有任何存儲。 (處理執行許可留作練習。)如果您發現sscanf格式的字符串對您的問題特別方便,這很有意義。否則,正則表達式可能是要走的路(不是在C標準中,但很容易找到一個實現)。