Как разбить строку на токены в C?

Как разбить строку на токены '&' в С?

5 ответов

Решение

strtok / strtok_r

char *token;
char *state;

for (token = strtok_r(input, "&", &state);
     token != NULL;
     token = strtok_r(NULL, "&", &state))
{
    ...
}

Я бы сделал это примерно так (используя strchr()):

#include <string.h>

char *data = "this&&that&other";
char *next;
char *curr = data;
while ((next = strchr(curr, '&')) != NULL) {
    /* process curr to next-1 */
    curr = next + 1;
}
/* process the remaining string (the last token) */

strchr(const char *s, int c) возвращает указатель на следующее местоположение c в s, или же NULL если c не найден в s,

Вы могли бы использовать strtok() Однако мне не нравится strtok(), так как:

  • он изменяет токенизируемую строку, поэтому он не работает для литеральных строк или не очень полезен, если вы хотите сохранить строку для других целей. В этом случае вы должны сначала скопировать строку во временную.
  • он объединяет соседние разделители, поэтому, если ваша строка была "a&&b&c" возвращенные токены "a", "b", а также "c", Обратите внимание, что нет пустого токена после "a",
  • это не потокобезопасно.

Вы можете использовать функцию strok(), как показано в примере ниже.

/// Function to parse a string in separate tokens 

int parse_string(char pInputString[MAX_STRING_LENGTH],char *Delimiter,
                   char *pToken[MAX_TOKENS])
{
  int i;
  i = 0;

  pToken[i] = strtok(pInputString, Delimiter);
  i++;

  while ((pToken[i] = strtok(NULL, Delimiter)) != NULL){
     i++;
  }
  return i;
}

/// The array pTokens[] now contains the pointers to the start of each token in the (unchanged) original string.

sprintf(String,"Token1&Token2");
NrOfParameters = parse_string(String,"&",pTokens);

sprintf("%s, %s",pToken[0],pToken[1]);

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

      #include <stdlib.h>
#include <string.h>
#define MAX_WORD_LEN 32


char **txtspt(const char *text, char split_char, int *w_count)
{
    if(strlen(text) <= 1) 
        return NULL;

    char **cpy0 = NULL;
    int i, j = 0, k = 0, words = 1;

    //Words counting
    for(i = 0; i < strlen(text); ++i)
    {
        if(text[i] == split_char && text[i + 1] != '\0')
        {
            ++words;
        }
    }
    //Memory reservation
    cpy0 = (char **) malloc(strlen(text) * words);
    for(i = 0; i < words; ++i)
    {
        cpy0[i] = (char *) malloc(MAX_WORD_LEN);
    }

    //Splitting
    for(i = 0; i < strlen(text) + 1; ++i)
    {
       if(text[i] == split_char)
       {
           cpy0[k++][j] = '\0';
           j = 0;
       }
       else
       {
           if(text[i] != '\n')           //Helpful, when using fgets() 
                cpy0[k][j++] = text[i];  //function
       }

    }

    *w_count = words;
    return cpy0;
}

Это довольно просто:

      char str[] = "&a&&b&c"; // a mutable string

for (char *cp = str; (cp = strtok(cp, "&")) != NULL; cp = NULL) {
    /* do something with the token */
}

Имеется один вызов , один экземпляр строки-разделителя и область действияcpсодержится внутри этого цикла.

Предложение использоватьstrchr()не учитывает несколько символов-разделителей. Возможно, было бы лучше, если бы это предложилиstrcspn(). Обратите внимание, что последний токен должен быть обработан ПОСЛЕ завершения цикла. Не очень удачный дизайн...

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

Другие вопросы по тегам