Токенизация строк в C

Я пытаюсь обозначить строку, используя пробел, как разделитель, но это не работает. Есть ли у кого-нибудь предложение о том, почему он не работает?

Изменить: токенизация с использованием:

strtok(string, " ");

Код выглядит следующим образом

pch = strtok (str," ");
while (pch != NULL)
{
  printf ("%s\n",pch);
  pch = strtok (NULL, " ");
}

Ответ 1

Сделайте это так:

char s[256];
strcpy(s, "one two three");
char* token = strtok(s, " ");
while (token) {
    printf("token: %s\n", token);
    token = strtok(NULL, " ");
}

Примечание: strtok изменяет строку на ее токенизацию, поэтому она не может быть const char*.

Ответ 2

Здесь пример использования strtok, помните, что strtok разрушает его входную строку (и поэтому никогда не может использоваться в строковой константе

char *p = strtok(str, " ");
while(p != NULL) {
    printf("%s\n", p);
    p = strtok(NULL, " ");
}

В основном следует отметить, что передача NULL в качестве первого параметра в strtok говорит ему, чтобы он получил следующий токен из строки, которая была ранее добавлена ​​в токенизацию.

Ответ 3

strtok может быть очень опасным. Он не является потокобезопасным. Его предполагаемое использование должно вызываться снова и снова в цикле, передавая результат с предыдущего вызова. Функция strtok имеет внутреннюю переменную, которая хранит состояние вызова strtok. Это состояние не уникально для каждого потока - оно глобально. Если какой-либо другой код использует strtok в другом потоке, у вас возникают проблемы. Не те проблемы, которые вы хотите отслеживать!

Я бы рекомендовал искать реализацию регулярного выражения или использовать sscanf, чтобы разделить строку.

Попробуйте следующее:

char strprint[256];
char text[256];
strcpy(text, "My string to test");
while ( sscanf( text, "%s %s", strprint, text) > 0 ) {
   printf("token: %s\n", strprint);
}

Примечание. Строка "текст" уничтожается по мере ее разделения. Это не может быть предпочтительным поведением =)

Ответ 4

Вы можете упростить код, введя дополнительную переменную.

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

int main()
{
    char str[100], *s = str, *t = NULL;

    strcpy(str, "a space delimited string");
    while ((t = strtok(s, " ")) != NULL) {
        s = NULL;
        printf(":%s:\n", t);
    }
    return 0;
}

Ответ 5

Я сделал некоторые строковые функции, чтобы разделить значения, используя меньшее количество указателей, поскольку я мог, потому что этот код предназначен для работы на процессорах PIC18F. Эти процессоры не очень хорошо справляются с указателями, когда у вас мало свободной памяти:

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

char POSTREQ[255] = "pwd=123456&apply=Apply&d1=88&d2=100&pwr=1&mpx=Internal&stmo=Stereo&proc=Processor&cmp=Compressor&ip1=192&ip2=168&ip3=10&ip4=131&gw1=192&gw2=168&gw3=10&gw4=192&pt=80&lic=&A=A";

int findchar(char *string, int Start, char C) {
    while((string[Start] != 0)) { Start++; if(string[Start] == C) return Start; }
    return -1;
}

int findcharn(char *string, int Times, char C) {
   int i = 0, pos = 0, fnd = 0;

    while(i < Times) {
       fnd = findchar(string, pos, C);
        if(fnd < 0) return -1;
        if(fnd > 0) pos = fnd;
       i++;
   }
   return fnd;
}

void mid(char *in, char *out, int start, int end) {
    int i = 0;
    int size = end - start;

    for(i = 0; i < size; i++){
        out[i] = in[start + i + 1];
    }
    out[size] = 0;
}

void getvalue(char *out, int index) {
    mid(POSTREQ, out, findcharn(POSTREQ, index, '='), (findcharn(POSTREQ, index, '&') - 1));
}

void main() {
   char n_pwd[7];
   char n_d1[7];

   getvalue(n_d1, 1);

   printf("Value: %s\n", n_d1);
} 

Ответ 6

При чтении документации strtok я вижу, что вам нужно передать указатель NULL после первого вызова "инициализации". Может быть, вы этого не сделали. Конечно, конечно.

Ответ 7

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

Эта функция является частью лицензированной библиотеки BSD, называемой zString. Вы более чем можете внести свой вклад:)

https://github.com/fnoyanisi/zString

char *zstring_strtok(char *str, const char *delim) {
    static char *static_str=0;      /* var to store last address */
    int index=0, strlength=0;       /* integers for indexes */
    int found = 0;                  /* check if delim is found */

    /* delimiter cannot be NULL
    * if no more char left, return NULL as well
    */
    if (delim==0 || (str == 0 && static_str == 0))
        return 0;

    if (str == 0)
        str = static_str;

    /* get length of string */
    while(str[strlength])
        strlength++;

    /* find the first occurance of delim */
    for (index=0;index<strlength;index++)
        if (str[index]==delim[0]) {
            found=1;
            break;
        }

    /* if delim is not contained in str, return str */
    if (!found) {
        static_str = 0;
        return str;
    }

    /* check for consecutive delimiters
    *if first char is delim, return delim
    */
    if (str[0]==delim[0]) {
        static_str = (str + 1);
        return (char *)delim;
    }

    /* terminate the string
    * this assignmetn requires char[], so str has to
    * be char[] rather than *char
    */
    str[index] = '\0';

    /* save the rest of the string */
    if ((str + index + 1)!=0)
        static_str = (str + index + 1);
    else
        static_str = 0;

        return str;
}

Как упоминалось в предыдущих сообщениях, поскольку strtok() или тот, который я вложил выше, полагается на переменную static *char, чтобы сохранить местоположение последнего разделителя между последовательными вызовами, следует проявлять особую осторожность при работе с многопоточными мки.

Ответ 8

int not_in_delimiter(char c, char *delim){

    while(*delim != '\0'){
            if(c == *delim) return 0;
            delim++;
    }
    return 1;
}

char *token_separater(char *source, char *delimiter, char **last){

char *begin, *next_token;
char *sbegin;

/*Get the start of the token */
if(source)
  begin = source;
else
  begin = *last;

sbegin = begin;

/*Scan through the string till we find character in delimiter. */
while(*begin != '\0' && not_in_delimiter(*begin, delimiter)){
       begin++;
}

/* Check if we have reached at of the string */
if(*begin == '\0') {
/* We dont need to come further, hence return NULL*/
   *last = NULL;
    return sbegin;
}
/* Scan the string till we find a character which is not in delimiter */
 next_token  = begin;
 while(next_token != '\0' && !not_in_delimiter(*next_token, delimiter))    {
    next_token++;
 }
 /* If we have not reached at the end of the string */
 if(*next_token != '\0'){
  *last = next_token--;
  *next_token = '\0';
   return sbegin;
}
}

 void main(){

    char string[10] = "abcb_dccc";
    char delim[10] = "_";
    char *token = NULL;
    char *last = "" ;
    token  = token_separater(string, delim, &last);
    printf("%s\n", token);
    while(last){
            token  = token_separater(NULL, delim, &last);
            printf("%s\n", token);
    }

}

Вы можете прочитать подробный анализ в блоге, указанном в моем профиле:)