0
char *args[32];
char **next = args;
char *temp = NULL;
char *quotes = NULL;

temp = strtok(line, " \n&");

while (temp != NULL) {
    if (strncmp(temp, "\"", 1) == 0) {
        //int i = strlen(temp);
        printf("first if");
        quotes = strtok(temp, "\"");    
    } else if (strncmp(temp, "\"", 1) != 0) {
        *next++ = temp;
        temp = strtok(NULL, " \n&");
    }
}

文字列の一部が引用符で囲まれている場合、スペースを保持する方法を理解するのに苦労しています。たとえば、execvp() にこれを実行させたい場合: diff "space name.txt" sample.txt、args[0] に diff、args[1] に space name.txt、args[ に sample.txt を保存する必要があります。 2]。

これを実装する方法がよくわかりません.ifステートメントを使用していくつかの異なるロジックを試しましたが、まだ十分ではありません. 現時点では、ls "folder" のような簡単なことをしようとしていますが、printf() ステートメントを出力する while ループでスタックします。

これは質問として表現されていないことを知っています-それは私が達成しようとしていることと私がこれまでのところどこにいるのかをより説明していますが、私は問題を抱えており、ロジックがどうあるべきかについてのヒントを本当に感謝しています.

4

5 に答える 5

1

使用する代わりにstrtok、文字列 char を char ごとに処理します。が表示された場合は"、フラグを設定します。フラグがすでに設定されている場合は、代わりに設定を解除してください。スペースがある場合は、フラグを確認して、次の引数に切り替えるか、現在の引数にスペースを追加してください。その他の文字 - 現在に追加します。ゼロ バイト - 処理が完了しました。

余分な努力をすれば、次のようなものでも処理できるようになります(結果として,をdiff "file \"one\"" file\ two取得する必要があります) 。difffile "one"file two

于 2013-03-25T13:06:53.690 に答える
0

ここに私の考えがあります:

  1. 最初は文字列の最初の文字を指す2 つのポインターAとを作成します。B
  2. Aスペースでない限り、すべての char を配列にコピーして、 pointer を使用して文字列を反復処理します。
  3. に到達したら、その位置から"ポインタを取り、次の に到達するまで、スペースを含むすべてをコピーします。BA+1"
  4. char から始めて、番号 2 から繰り返しB+1ます。
  5. に達していない限り繰り返します\0

注:ただし、引用符がネストされている場合はどうするかを検討する必要があります。

フラグ (int 1 || 0) とポインターを使用して、引用符で囲まれているかどうかを示すこともできます。フラグに基づく 2 つの個別のルールに従ってください。

于 2013-03-25T13:21:28.507 に答える
0

3 つの関数を記述します。これらはすべて、処理するバイト数を返す必要があります。まず、引用符で囲まれた引数を処理するものです。

size_t handle_quoted_argument(char *str, char **destination) {
    assert(*str == '\"');
    /* discard the opening quote */
    *destination = str + 1;

    /* find the closing quote (or a '\0' indicating the end of the string) */
    size_t length = strcspn(str + 1, "\"") + 1;
    assert(str[length] == '\"'); /* NOTE: You really should handle mismatching quotes properly, here */

    /* discard the closing quote */
    str[length] = '\0';
    return length + 1;
}

... 次に、引用符で囲まれていない引数を処理する関数:

size_t handle_unquoted_argument(char *str, char **destination) {
    size_t length = strcspn(str, " \n");
    char c = str[length];
    *destination = str;
    str[length] = '\0';
    return c == ' ' ? length + 1 : length;
}

...次に、(おそらく繰り返しの)空白を処理する関数:

size_t handle_whitespace(char *str) {
    int whitespace_count;
    /* This will count consecutive whitespace characters, eg. tabs, newlines, spaces... */
    assert(sscanf(str, " %n", &whitespace_count) == 0);
    return whitespace_count;
}

これら 3 つの組み合わせは簡単です。

size_t n = 0, argv = 0;
while (line[n] != '\0') {
    n += handle_whitespace(line + n);
    n += line[n] == '\"' ? handle_quoted_argument(line + n, args + argv++)
                         : handle_unquoted_argument(line + n, args + argv++);
}

これを 4 つの個別のアルゴリズムに分割すると、このタスクがどれほど簡単になるかがわかりますか?

于 2013-03-25T13:34:08.403 に答える
0

だからここに私が読んだところがあります:

while((qtemp = fgets(line, size, stdin)) != NULL ) {
    if (strcmp(line, "exit\n") == 0) {
        exit(EXIT_SUCCESS);
    }
    spaceorquotes(qtemp);
}    

それから私はこれに行きます: (私はイニシャライザを追加していませんが、あなたはアイデアを得るでしょう)

length = strlen(qtemp);
for(i = 0; i < length; i++) {
    position = strcspn(qtemp, " \"\n");
    while (strncmp(qtemp, " ", 1) == 0) {   
        memmove(qtemp, qtemp+1, length-1);
        position = strcspn(qtemp, " \"\n");
    } /*this while loop is for handling multiple spaces*/

    if (strncmp(qtemp, "\"", 1) == 0) { /*this is for handling quotes */    
        memmove(qtemp, qtemp+1, length-1);
        position = strcspn(qtemp, "\"");
        stemp = malloc(position*sizeof(char));
        strncat(stemp, qtemp, position);
        args[i] = stemp;
    } else {      /*otherwise handle it as a (single) space*/
        stemp = malloc(position*sizeof(char));
        strncat(stemp, qtemp, position); 
        args[i] = stemp;
    }
    //printf("args: %s\n", args[i]);
    length = strlen(qtemp);
    memmove(qtemp, qtemp+position+1, length-position);
}
args[i-1] = NULL; /*the last position seemed to be a space, so I overwrote it with a null to terminate */
if (execvp(args[0], args) == -1) {
    perror("execvp");
    exit(EXIT_FAILURE);
}

変更可能な左辺値が示唆するように、strcspn を使用すると役立つことがわかりました。

于 2013-03-26T20:55:23.960 に答える
0

あなたが何をしようとしているのか理解することさえ私は混乱しています。入力文字列をスペースで区切られたトークンにトークン化しようとしていますか?

入力文字列をスペースで区切るだけで、二重引用符文字に遭遇すると、引用符で囲まれた文字列を処理する 2 番目の内部ループが必要になります。

引用符で囲まれた文字列には、終了引用符を検索するだけではありません。たとえば、バックスラッシュでエスケープされた引用符やバックスラッシュでエスケープされたバックスラッシュなど、バックスラッシュを処理する必要があります。

次のことを考慮してください。

diff "space name \" with quotes.txt\\" foo

(くだらない) filename を参照しますspace name " with quotes.txt\。これをテストケースとして使用すると、基本がいつ完了したかがわかります。シェル コマンド ラインの分割は、それよりもはるかにクレイジーであることに注意してください。

于 2013-03-25T13:08:34.033 に答える