用C语言读取文件

用C语言读取文件,c,parsing,file-io,tokenize,strtok,C,Parsing,File Io,Tokenize,Strtok,我有一个需要提取单词的输入文件。单词只能包含字母和数字,因此其他任何内容都将被视为分隔符。我试过fscanf、fgets+sscanf和strtok,但似乎没有任何效果 while(!feof(file)) { fscanf(file,"%s",string); printf("%s\n",string); } 上面的一行显然不起作用,因为它不使用任何分隔符,所以我将该行替换为: fscanf(file,"%[A-z]",string); 它可以很好地读取第一个单词,但文件

我有一个需要提取单词的输入文件。单词只能包含字母和数字,因此其他任何内容都将被视为分隔符。我试过fscanf、fgets+sscanf和strtok,但似乎没有任何效果

while(!feof(file))
{
    fscanf(file,"%s",string);
    printf("%s\n",string);
}
上面的一行显然不起作用,因为它不使用任何分隔符,所以我将该行替换为:

 fscanf(file,"%[A-z]",string);
它可以很好地读取第一个单词,但文件指针会不断倒带,所以它会一遍又一遍地读取第一个单词

因此,我使用fgets阅读第一行并使用sscanf:

sscanf(line,"%[A-z]%n,word,len);
line+=len;
这个也不行,因为无论我怎么做,我都无法将指针移动到正确的位置。我试过strtok,但找不到如何设置定界符

while(p != NULL) {
printf("%s\n", p);
p = strtok(NULL, " ");
这一个显然把空白字符作为定界符,但我有100个定界符


因为从文件中提取单词一开始似乎是一个简单的概念,但我尝试的方法都不管用,所以我在这里遗漏了什么吗?

考虑构建一个最小值。在状态词中,只要它看到字母和数字,它就会留在状态词中。当遇到其他内容时,它将切换到状态分隔符。然后它可以在状态分隔符中执行完全相反的操作

下面是一个简单状态机的示例,可能会有所帮助。为简洁起见,它仅适用于数字
echo“2341452(42 555”|/main
将在单独的行中打印每个数字。它不是一个lexer,但在状态之间切换的想法非常相似

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

int main() {
  static const int WORD = 1, DELIM = 2, BUFLEN = 1024;
  int state = WORD, ptr = 0;
  char buffer[BUFLEN], *digits = "1234567890";
  while ((c = getchar()) != EOF) {
    if (strchr(digits, c)) {
      if (WORD == state) {
        buffer[ptr++] = c;
      } else {
        buffer[0] = c;
        ptr = 1;
      }
      state = WORD;
    } else {
      if (WORD == state) {
        buffer[ptr] = '\0';
        printf("%s\n", buffer);
      }
      state = DELIM;
    }
  }
  return 0;
}
#包括
#包括
int main(){
静态常量int WORD=1,DELIM=2,BUFLEN=1024;
int state=WORD,ptr=0;
字符缓冲区[BUFLEN],*digits=“1234567890”;
而((c=getchar())!=EOF){
if(strchr(数字,c)){
if(WORD==状态){
缓冲区[ptr++]=c;
}否则{
缓冲区[0]=c;
ptr=1;
}
状态=单词;
}否则{
if(WORD==状态){
缓冲区[ptr]='\0';
printf(“%s\n”,缓冲区);
}
国家=德利姆;
}
}
返回0;
}

如果状态数增加,可以考虑替换<代码>如果语句检查当前状态,使用“代码>开关< /代码>块。通过将整个输入块读取到临时缓冲区并迭代它,可以提高性能。


如果必须处理更复杂的输入文件格式,您可以使用词法分析器生成器,例如。它们可以为您定义状态转换和词法生成器生成的其他部分。

您的分隔符是什么?
strtok
的第二个参数应该是包含分隔符的字符串,第一个参数是第一轮应该是指向字符串的指针,然后是
NULL

char * p = strtok(line, ","); // assuming a , delimiter
printf("%s\n", p);

while(p)
{
    p = strtok(NULL, ",");
    printf("%S\n", p);
} 
我将使用:

FILE *file;
char string[200];

while(fscanf(file, "%*[^A-Za-z]"), fscanf(file, "%199[a-zA-Z]", string) > 0) {
    /* do something with string... */
}
这将跳过非字母,然后读取最多199个字母的字符串。唯一奇怪的是,如果您有任何长度超过199个字母的“单词”,它们将被拆分为多个单词,但您需要限制以避免缓冲区溢出…

几点:

首先,不要使用
feof(file)
作为循环条件;
feof
在尝试读取文件末尾之前不会返回
true
,因此循环执行次数过多

第二,你提到:

fscanf(文件“%[A-z]”,字符串);


它可以很好地读取第一个单词,但文件指针会不断倒带,所以它会一遍又一遍地读取第一个单词。 事实并非如此;如果流中的下一个字符与格式说明符不匹配,
scanf
在没有读取任何内容的情况下返回,并且
string
未被修改

这里有一个简单但不雅观的方法:它一次从输入文件中读取一个字符,检查它是字母还是数字,如果是,则将其添加到字符串中

#include <stdio.h>
#include <ctype.h>

int get_next_word(FILE *file, char *word, size_t wordSize)
{
  size_t i = 0;
  int c;

  /**
   * Skip over any non-alphanumeric characters
   */
  while ((c = fgetc(file)) != EOF && !isalnum(c))
    ; // empty loop

  if (c != EOF)
    word[i++] = c;

  /**
   * Read up to the next non-alphanumeric character and
   * store it to word
   */
  while ((c = fgetc(file)) != EOF && i < (wordSize - 1) && isalnum(c))
  {
      word[i++] = c;
  }
  word[i] = 0;
  return c != EOF;
}

int main(void)
{
   char word[SIZE]; // where SIZE is large enough to handle expected inputs
   FILE *file;
   ...
   while (get_next_word(file, word, sizeof word))
     // do something with word
   ...
}
#包括
#包括
int获取下一个单词(文件*文件,字符*单词,大小\u t字号)
{
尺寸i=0;
INTC;
/**
*跳过任何非字母数字字符
*/
而((c=fgetc(file))!=EOF&&!isalnum(c))
;//空循环
如果(c!=EOF)
字[i++]=c;
/**
*最多读取下一个非字母数字字符,然后
*将其存储到word
*/
while((c=fgetc(file))!=EOF&i<(字号-1)和&isalnum(c))
{
字[i++]=c;
}
字[i]=0;
返回c!=EOF;
}
内部主(空)
{
char word[SIZE];//其中的大小足够大,可以处理预期的输入
文件*文件;
...
while(获取下一个单词(文件、单词、单词大小))
//用word做些什么
...
}

定界符是除a-z和a-z之外的所有东西。