繁体   English   中英

strtok问题,它无法按预期工作

[英]strtok issue, it doesn't work as expected

我有一个读取格式化文件的功能。 看起来像这样:

1;Name_of_the_author;The date when the quote was published;The author of the quote;The quote
2;Name_of_the_author_2;The date when the second quote was published;The author of the second quote;The second quote

因此,定界符为; 我要做的是检查每个序列/令牌并检查是否正确。 但是,问题在于,它没有获得所有令牌,仅获得前三个令牌,在中断日期之后,它不会遍历...这是附加的代码功能。 忽略注释,它用于学校项目,注释以罗马尼亚语显示。

int svnCheckDb()
{
    FILE *file;
    int k, p, i=2, m, j=0;
    char mystring[1000000], *var, *var2, *string;
    file = fopen("db.txt", "r"); //deschidem fisierul
    if(file == NULL) {
        return 0;
    }
    else {
         //il putem accesa.
        while(fgets(mystring, 1000000, file) ) {
            if(j != 0)
            {
                //nu luam si prima linie cu descrierea repo-ului, prelucram doar citatele, j-ul numara randul pe care suntem
                //separam cu strtok linia citita si verificam fiecare informatie in parte pentru a fi corecta
                var = strtok(mystring, ";");
                k=1;
                /*
                k numara string-urile citite din descrierea citatelor tocmai citita. Primul e numarul de ordine, al doilea e utilizatorul
                care a adaugat citatul, al treilea reprezinta data adaugarii citatului, dupa care urmeaza citatul.
                */
                while(var != NULL) {
                    printf("k is %d and var is %s \n", k, var);
                    switch(k)
                    {
                        case 1:
                           //numarul de ordine. Daca e 0, inseamna ca nu e numar, returnam false
                            i = atoi(var);
                            if(i == 0)
                                return 0;
                            break;
                        case 2:
                            //utilizatorul care a adaugat citatul. Daca e gol sau nu e format doar din caractere a-z A-Z, returnam false
                            for( m = 0; m < strlen(var); m++ )
                                if(!isalpha(var[m]))
                                   return 0;
                            break;
                        case 3:
                            //data la care a fost adaugat citatul. Intrucat folosim formatul DD MM YY cu spatii intre ele, vom verifica daca e ok in fisier
                            string = var;
                            var2 = strtok(string, " ");
                            p=1; //folosim p sa vedem daca am ajuns la zi, luna sau an
                            while(var2 != NULL)
                            {
                                switch(p)
                                {
                                    case 1:
                                        //ziua
                                        i = atoi(var2);
                                        if(i == 0)
                                            return 0;
                                        else if(i > 31 || i < 1)
                                            return 0;
                                        break;
                                    case 2:
                                        //luna, care e formata din primele 3 caractere ale lunii si trebuie sa respecte formatul acesta
                                        if( strlen(var2) == 3)
                                        {
                                            for( m = 0; m < strlen(var2); m++ )
                                                if(!isalpha(var2[m]))
                                                    return 0;
                                        }
                                        else return 0;
                                        break;
                                    case 3:
                                        //anul.
                                        i = atoi(var2);
                                        if(i == 0)
                                            return 0;
                                        break;
                                }

                                var2 = strtok(NULL, " ");
                                p++;
                            }
                            break;
                        case 4:
                            //cine a adaugat citatul, vom folosi functia searchAuthor dupa ce va fi gata.
                            for( m = 0; m < strlen(var); m++ )
                                if(!isalpha(var[m]))
                                   return 0;
                            break;
                        case 5:
                            //citatul
                            if(strlen(var) == 0)
                                return 0;
                            printf("%d x \n", strlen(var));
                    }
                    var = strtok(NULL, ";"); //trecem la urmatorul sir de car separat de ;
                    k++;
                }
            }
            j++; //trecem la urmatoarea linie
        }
    }
    return 1;
}

k仅取3,因此仅取数字,作者和日期。 没有报价,也没有作者。 所以我无法检查它们是否正确

这里:

string = var;
var2 = strtok(string, " ");

你惹上麻烦了。 strtok忘记了它曾经有一个更长的字符串来进行标记化,现在它所记住的只是它先前返回的部分。 您可以在同一时间与tokenise不同的字符串strtok_r 阅读手册页以获取更多详细信息。

如果strtok_r不可用,则在您的情况下,这是在case 3不使用strtok case 3在内部循环中进行解析的最简单方法。 由于期望的格式是固定的,因此按顺序检查三个字段并不复杂。 如果您敢,还可以存储strtok插入缓冲区的'\\ 0'字节的位置,在内循环之后,根据需要用''或';'替换它们,并输入重新修改的字节再次缓冲到strtok 但这很容易出错,我强烈建议您不要尝试这样做。

您可以从删除第一个循环和其他变量开始。 第一个strtok必须位于循环之外,该循环将帮助您划分每个令牌,这是为了将要处理的缓冲区存储在strtok函数中而完成的。 在确定不再要分割主数据之前,您无法重用strtok函数,因为如果在主处理结束之前重用strtok,则会重置strtok函数使用的数据。 例:

char str[] = "hello world how are you?\n";
char *res;
// here i tell strtok the string str is the one i want to separate
res = strtok(str, " \n");
int i = 0;
// here i separate str, using the caracters space and endline as separators
while (res != null)
{
 res = strtok(NULL, " \n"); // each time i pass in this part of the loop i get my new     word in res
 ++i; // here the variable i represents the number of times i enter the loop
}

// here i can use again strtok with another string

如果您的分配中允许使用sscanf函数,并且由于您似乎知道文件的确切格式,则可能要使用它。 另外,getline函数还允许您逐行获取文件,并且可以一次处理每个句子。

示例strtok代码,创建指向strtok每个元素的指针的数组。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_SPLIT 10

void split(char **result, char *working, const char *delim)
{
          int i;
          char *p=strtok(working, delim);
          for(i=0; p!=NULL && i<MAX_SPLIT; p=strtok(NULL, delim), i++ )
          {
              result[i]=p;
              result[i+1]=NULL;
          }
}

int foo(const char *splitme, const char *delim)
{
    int retval=0;
    char *result[MAX_SPLIT]={NULL};
    char *working=strdup(splitme);
    int i=0;
    if(working!=NULL)
    {
          split(result, working, delim);
        retval=1;
        while(result[i]!=NULL)        
              printf("%s\n", result[i++]);                     
        free(working);      
    }
    return retval;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM