2

私はこのような文字列を持っています:

"00:00:00 000~00:02:00 0000|~00:01:00 0000;00:01:00 0000~"

のようなアイテムをそれぞれ取得したい"00:00:00 000"

私の考えでは、最初に文字列を";"で分割し、次に で分割し"|"、最後に で分割し"~"ます。

しかし、問題は、のよう"00:01:00 0000~"に nullの場合は取得できないことです"~"。取得してデフォルト値を設定し、別の場所に保存したいのですが、コードが機能しません。何が問題ですか?

これが私のコードです:

int main(int argc, char *argv[])
{

   char *str1, *str2, *str3, *str4, *token, *subtoken, *subt1, *subt2;
   char *saveptr1, *saveptr2, *saveptr3;
   int j;

   for (j = 1, str1 = argv[1]; ; j++, str1 = NULL) {
       token = strtok_r(str1, ";", &saveptr1);
       if (token == NULL)
           break;
       printf("%d: %s\n", j, token);

       int flag1 = 1; 
       for (str2 = token; ; str2 = NULL) {
           subtoken = strtok_r(str2, "|", &saveptr2);
           if (subtoken == NULL)
               break;
           printf("  %d: --> %s\n", flag1++, subtoken);
           int flag2 = 1;
           for(str3 = subtoken; ; str3 = NULL) {
                subt1 = strtok_r(str3, "~", &saveptr3);
                if(subt1 == NULL) {
                    break;
                }
                printf("      %d: --> %s\n",flag2++, subt1);
           }
       }
   }

   exit(EXIT_SUCCESS);
} /* main */
4

3 に答える 3

2

最初にすべての区切り文字を統一すると、アルゴリズムを簡素化できます。最初に、および | の出現箇所をすべて置き換えます。~ を使用すると、解析が容易になります。これは、sed または vim を介して外部的に行うか、C コードでプログラムによって行うことができます。そうすれば、「NULL」問題を簡単に取得できるはずです。(個人的には、strtok は元の文字列を変更するため、使用しないことを好みます)。

于 2012-09-11T10:11:48.037 に答える
2

この場合、カスタム パーサーを作成する方が簡単です。

以下のバージョンでは、新しい文字列を割り当てます。新しいメモリを割り当てたくない場合は、add_stringメソッドを代わりに単に を指すように変更し、 0startに設定します。start[len]

static int add_string( char **into, const char *start, int len )
{
    if( len<1 ) return 0;
    if( (*into = strndup( start, len )) )
        return 1;
    return 0;
}

static int is_delimeter( char x )
{
    static const char delimeters[] = { 0, '~', ',', '|',';' };
    int i;

    for( i=0; i<sizeof(delimeters); i++ )
        if( x == delimeters[i] )
            return 1;

    return 0;
}

static char **split( const char *data )
{
    char **res = malloc(sizeof(char *)*(strlen(data)/2+1));
    char **cur = res;
    int last_delimeter = 0, i;

    do {
        if( is_delimeter( data[i] ) )
        {
            if( add_string( cur, data+last_delimeter,i-last_delimeter) )
                cur++;
            last_delimeter = i+1;
        }
    } while( data[i++] );

    *cur = NULL;
    return res;
}

メソッドの使用例:

int main()
{
    const char test[] = "00:00:00 000~00:02:00 0000|~00:01:00 0000;00:01:00 0000~";
    char **split_test = split( test );
    int i = 0;

    while( split_test[i] )
    {
        fprintf( stderr, "%2d: %s\n", i, split_test[i] );
        free( split_test[i] );
        i++;
    }
    free( split_test );
    return 0;
}
于 2012-09-11T12:42:03.180 に答える
1

文字列を分割する代わりに、文字列を解析する単純な有限状態マシンを作成する方が適している場合があります。幸いなことに、トークンの長さには上限があるようです。これにより、作業がはるかに簡単になります。

文字列を繰り返し処理し、4 つの異なる状態を区別します。

  • 現在の文字は区切り文字ではありませんが、前の文字は (トークンの開始) でした
  • 現在の文字は区切り文字で、前の文字は区切り文字ではありません (トークンの終わり)
  • 現在の文字と前の文字はどちらも区切り文字ではありません (一時バッファーに格納します)
  • 現在の文字と前の文字は両方とも区切り文字です (無視して次の文字を読み取ります)

指定されたとおりに文字列を解析する、非常に短く (10 行?) 簡潔なコードを作成できるはずです。

于 2012-09-11T10:59:52.983 に答える