5

読み取り文字列に含めることができる文字に関しては、非常に厳密にする必要があります。

一連の空白の後に文字が続き、一連の空白が続きます。
例: " c ""c"""" "

文字を無視できるフォーマット指定子を見つける必要がありますが、それがこの特定の文字であり、他の文字ではない場合に限られます。このシーケンス" e "は中止する必要があります。

試してみ" %*[c] "ましたが、一部のシナリオで単体テストが失敗するため、 0 個以上ではなく" %*[c] "1 個以上を探していると思い込んでしまいました。'c''c'

私の問題をよりよく説明するのに役立つ小さな例を書きました。これは最小限の例にすぎないことに注意してください。中心的な問題は、ゼロまたは単一文字の量をどのように解析するかです。

#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

1 に答える 1

4

他の人があなたに指摘したように、sscanfこの目的での使用はお勧めできません。キャッチできないのは、と の(間に表示される場合と表示されない場合がある「オプション」です。では、欠落していることを示す区切り文字がまったくないオプションのフィールドがある場合、欠落していると判断する唯一の方法は、それを解析して、そこにないことに気づき、もう一度解析することです。別のスキャン形式文字列を使用します。"Xscanf

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配列は にあるものよりも 1 つ多いのです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);
于 2013-05-24T17:24:12.787 に答える