дважды разбить строку на c с помощью strtok () - PullRequest
8 голосов
/ 28 декабря 2010

Я использую strtok() в c для анализа строки csv. Сначала я токенизирую его, чтобы просто узнать, сколько токенов существует, чтобы я мог выделить строку правильного размера. Затем я использую ту же переменную, что и в прошлый раз для токенизации. Каждый раз, когда я делаю это во второй раз, он strtok(NULL, ",") возвращает NULL, хотя есть еще больше токенов для анализа. Может кто-нибудь сказать мне, что я делаю не так?

char* tok;
int count = 0;
tok = strtok(buffer, ",");
while(tok != NULL) {
    count++;
    tok = strtok(NULL, ",");
}

//allocate array

tok = strtok(buffer, ",");
while(tok != NULL) {
    //do other stuff
    tok = strtok(NULL, ",");
}

Таким образом, в этот второй цикл while он всегда заканчивается после того, как найден первый токен, хотя токенов больше. Кто-нибудь знает, что я делаю не так?

Ответы [ 3 ]

18 голосов
/ 28 декабря 2010

strtok() изменяет строку, с которой он работает, заменяя символы-разделители нулями. Поэтому, если вы хотите использовать его более одного раза, вам придется сделать копию.

2 голосов
/ 02 января 2011

Используйте strsep - он фактически обновляет ваш указатель.В вашем случае вам придется продолжать вызывать NULL, а не передавать адрес вашей строки.Единственная проблема с strsep заключается в том, что если он был ранее размещен в куче, сохраните указатель на начало, а затем освободите его позже.

char * string;символ * токен;token = strsep (& string, ",");

strtok используется в вашем обычном введении в курс C - используйте strsep, это намного лучше.:-) Не запутывайтесь в "о, дерьмо - я должен пройти в NULL все еще, потому что strtok облажался мое позиционирование."

2 голосов
/ 28 декабря 2010

Не обязательно делать копию - strtok() действительно изменяет строку, которую он токенизирует, но в большинстве случаев это просто означает, что строка уже токенизирована, если вы хотите снова иметь дело с токенами.

Вот ваша программа, немного измененная для обработки токенов после вашего первого прохода:

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

int main()
{
    int i;
    char buffer[] = "some, string with  ,  tokens";

    char* tok;
    int count = 0;
    tok = strtok(buffer, ",");
    while(tok != NULL) {
        count++;
        tok = strtok(NULL, ",");
    }


    // walk through the tokenized buffer again
    tok = buffer;

    for (i = 0; i < count; ++i) {
        printf( "token %d: \"%s\"\n", i+1, tok);
        tok += strlen(tok) + 1;  // get the next token by skipping past the '\0'
        tok += strspn(tok, ","); //   then skipping any starting delimiters
    }

     return 0;
  }

Обратите внимание, что это, к сожалению, хитрее, чем я впервые опубликовал - вызов strspn() необходимо выполнить после пропуска '\ 0 'помещается на strtok(), так как strtok() пропустит любые начальные символы разделителя для возвращаемого токена (без замены символа разделителя в источнике).

...