2011-12-27 59 views
-1

我有一个读取格式化文件的函数。它看起来像这样:strtok问题,它不按预期工作

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,所以它只能得到数字,作者和日期。没有报价和没有作者。因此,我不能检查他们,看看它是否是真的

+0

它失败了,因为在情况3你再次用新字符串调用strtok(3)。不幸的是,你无法做到这一点,然后再次在外循环中使用strtok(3),你会这样做。您需要重新设计循环,以便在使用strtok(3)解析另一个字符串(空格)之前完成对第一个字符串的解析。 – 2011-12-27 20:16:52

+0

它按预期工作。 – 2011-12-27 21:18:06

+0

不是。 k停在3而不是去5 – FinalDestiny 2011-12-27 21:22:05

回答

1

你可以先把你的第一个循环带走,也可以从其他变量开始。 第一个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函数允许您逐行读取文件,并且可以一次处理每个句子。

+0

我知道了与sscanf一起工作,谢谢! – FinalDestiny 2011-12-27 21:50:18

3

这里:

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

你惹上麻烦。 strtok忘记它曾经有一个更长的字符串tokenise,现在它所记得的是它以前返回的部分。您可以使用strtok_r同时标记不同的字符串。阅读手册页获取更多细节。

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

+0

它似乎没有工作,我使用strtok_r时出现错误和很多警告,即使使用我在互联网上找到的语法 – FinalDestiny 2011-12-27 20:45:16

+0

我试过var = strtok_r(mystring,“ ; “&w);用于第一和strtok函数VAR = strtok_r(MyString的, ”;“。对于第二个,&q);我试图与图1和2,而不是q和W ...和错误是” BIN \调试\克里斯提cme2 。EXE ||致命错误LNK1120:1无法解析的外部|“和”main.obj ||错误LNK2019:无法解析的外部符号_strtok_r在函数_main中引用|“ – FinalDestiny 2011-12-27 20:49:50

+0

首先,你需要不同的'strtok_r's工作在不同的内存区域,所以你必须在'case 3:'中将'strcpy'部分加入'char *';其次,'strtok_r' - 至少在glibc中 - 仅对某些特性宏集合可用,例如'_POSIX_SOURCE'或'_BSD_SOURCE'或者其他几个。但是,它看起来像你在Windows上,你的C工具链可能没有'strtok_r',谷歌的'strtok_r'和'your_compiler'(MSVC,也许?)找出。 – 2011-12-27 21:02:47

0

示例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; 
}