2013-05-23 2 views
4

읽기 문자열에 포함될 수있는 문자와 관련하여 매우 엄격해야합니다.문자 집합에서 0 개 이상의 문자를 읽는 scanf 형식 지정자

일련의 공백이 있고 그 다음에 문자와 공백이옵니다.
예 : " c ", "c", """ "

나는 나를하지만이 특정 문자가 아닌 다른 문자 경우에만 문자를 무시 할 수있는 형식 지정자를 찾을 필요가있다. 이 시퀀스 " e "은 중단되어야합니다.

나는 " %*[c] " 시도했지만 내 unittests은 일부 시나리오 실패 - " %*[c] " 하나 이상의 대신에 0 개 이상의 'c''c'을 찾고 믿고 저를 선도.

나는 내 문제를 더 잘 설명하는 데 도움이되는 간단한 예를 썼다. 이것은 단지 최소한의 예에 불과하다는 것을 명심하십시오. 가장 중요한 문제는 어떻게 0 또는 하나의 문자 하나를 파싱하는지입니다. 이 목적을 위해 sscanf를 사용하여 다른 사람들이 당신에 표시된 것처럼

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

unsigned match(const char * formula){ 
    unsigned e = 0, found = 0, s; 
    char del; 
    int parsed, pos, len = (int) strlen(formula); 
    const size_t soc = sizeof(char); 
    del = ' '; 
    parsed = sscanf_s(formula, " \" %*[(] X%*[^>]>> %u %*[)] %c %n", &s, &del, soc, &pos);// (X >> s) 
    if((2 == parsed) && (pos == len) && ('"' == del)){ 
     printf("%6s:%s\n", "OK", formula); 
    }else{ 
     printf("%6s:%s\n", "FAIL", formula); 
     e += 1; 
    } 
    return e; 
} 

unsigned main(void) 
{ 
    unsigned e = 0; 

    printf("SHOULD BE OK\n"); 
    e += match("  \"X >> 3\""); //This one does not feature the optional characters 
    e += match("  \"(X >> 3) \""); 
    e += match("  \"(X >> 3) \"\r"); 

    printf("SHOULD FAIL\n"); 
    if (0 == match("  \"(Y >> 3) \"")) e += 1; 
    if (0 == match("  \"g X >> 3) \"")) e += 1; 
    if (0 == match("  \"(X >> 3.3-4.2) \"")) e += 1; 

    if(0 != e){ printf("ERRORS: %2u\n", e); } 
    else{ printf("all pass\n", e); } 
    return e; 
} 
+4

'scanf '는 범용 도구가 아닙니다. 'scanf '로 원하는 것을 구현하는 것은 불가능하다고 생각합니다. 대신 정규식이나 수동 구문 분석을 사용할 수 있습니다. – anatolyg

+4

나는 두 번째가있다, 나는 단지 이것보다 더 많은 시간을 waaay 지출 한 후에 포기했다. 살인자 인 두 번째 괄호입니다. –

답변

4

은 권장되지 않습니다. 붙잡을 수없는 경우는 "선택 사항"(이며 "X 사이에 나타나거나 나타나지 않을 수 있습니다. scanf을 사용하여 누락되었음을 나타내는 구분 기호가없는 선택 필드가있는 경우 누락되었음을 확인하는 유일한 방법은 구문 분석을 시도하고 거기에없는 것을 확인하고 구문 분석을 시도하는 것입니다 다시 다른 스캔 형식 문자열을 사용하십시오.

parsed = sscanf(formula, " \" %*[(] X%*[^>]>> %u %*[)] %c %n", &s, &del, &pos); 
if (parsed != 2) { 
    parsed = sscanf(formula, " \" X%*[^>]>> %u %c %n", &s, &del, &pos); 
} 

이 솔루션의 나머지 부분을 구문 분석 POSIX <regex.h> 기본 정규 표현식을 사용하는 방법에 대해 설명합니다.

먼저 정규 표현식을 정의하고 컴파일해야합니다.

const char *re = 
    "[ \t]*\""     /* match up to '"' */ 
    "[ \t]*(\\{0,1\\}[ \t]*" /* match '(' if present */ 
    "X[ \t]*>>[ \t]*"   /* match 'X >>' */ 
    "\\([0-9][0-9]*\\)"  /* match number as subexpression */ 
    "[ \t]*)\\{0,1\\}[ \t]*" /* match ')' if present */ 
    "\\(.\\)"     /* match final delimiter as subexpression */ 
    "[ \t\r\n]*";    /* match trailing whitespace */ 
regex_t reg; 
int r = regcomp(&reg, re, 0); 
if (r != 0) { 
    char buf[256]; 
    regerror(r, &reg, buf, sizeof(buf)); 
    fprintf(stderr, "regcomp: %s\n", buf); 
    /*...*/ 
} 

이제 일치시킬 문자열에 대해 식을 실행해야합니다. 컴파일러는 정규 표현식에서 부분 표현의 수를 추적하여 그 수를 reg.re_nsub에 넣습니다. 그러나 암시적인 서브 표현식은 그 수에 포함되지 않습니다. 그것은 제공된 표현식과 일치하는 완전한 문자열입니다. 이것은 항상 첫 경기에서 나타납니다. 따라서 일치하는 배열을 만들 때 그 배열을 고려하십시오. 그래서 matches 배열에는 reg.re_nsub에있는 것보다 하나 더 많은 배열이 있습니다.

unsigned match(const regex_t *preg, const char * formula){ 
    /*...*/ 
    int r; 
    const int NSUB = preg->re_nsub + 1; 
    regmatch_t matches[NSUB]; 

    r = regexec(preg, formula, NSUB, matches, 0); 
    if (r == 0) { 
     /* success */ 
     parsed = preg->re_nsub; 
     s = atoi(formula + matches[1].rm_so); 
     del = formula[matches[2].rm_so]; 
     pos = matches[0].rm_eo; 
    } else { 
     parsed = 0; 
    } 
    /*...*/ 

정규 표현식을 다 마쳤 으면 정규식을 완료해야합니다 (컴파일이 완료된 경우).

regfree(&reg);