c/c++语言开发共享从.txt文件中读取随机行

我正试图通过从.txt文件中读取随机单词来升级我的Hangman游戏。 事实是,我无法弄清楚如何从.txt文件中读取随机行。 .txt文件的每个新行都有单个单词。

void ler_palavras() { FILE *words; if ((words = fopen("words.txt", "r")) == NULL) { printf("Error! opening file"); exit(1); } // reads text until newline fscanf(words,"%[^n]", word); fclose(words); } 

    如果由于某种原因,您不能将整组行加载到内存(太大或其他),有一种方法可以从一组流条目中选择一个随机条目。 它不会无限缩放,它会表现出很小的偏见,但这是一个游戏,而不是加密,所以这不应该是一个破坏者。

    逻辑是:

    假设线的数量足够小(并且PRNG产生的double s的范围足够精细),则尽可能接近选择任何给定线的相等可能性; 对于两条线,每条线有50/50的射击,三个,33.33 ……%等。

    我现在缺少一个C编译器,但基本代码看起来像:

     /* Returns a random line (w/o newline) from the file provided */ char* choose_random_word(const char *filename) { FILE *f; size_t lineno = 0; size_t selectlen; char selected[256]; /* Arbitrary, make it whatever size makes sense */ char current[256]; selected[0] = ''; /* Don't crash if file is empty */ f = fopen(filename, "r"); /* Add your own error checking */ while (fgets(current, sizeof(current), f)) { if (drand48() < 1.0 / ++lineno) { strcpy(selected, current); } } fclose(f); selectlen = strlen(selected); if (selectlen > 0 && selected[selectlen-1] == 'n') { selected[selectlen-1] = ''; } return strdup(selected); } 

    rand()有其局限性,包括仅生成值0RAND_MAX ,文件可以有多次RAND_MAX行。 假设行数大约为RAND_MAX/10或更低,则以下内容将满足OP的目标。

    执行一次传递来计算行数。 – > lc

    对于所需的每个随机行,重新读取文件的行,从[0... lc-1]范围内的某个随机数之前的行索引开始。

    然后只需阅读并打印该行。 不需要行缓冲区。 该文件是行缓冲区。 代码重新使用Line_Count()进行总行数计算和读取直到第n行。

     #include  #include  #include  #include  #include  // Return line count, but stop once the count exceeds a maximum int Line_Count(FILE *istream, int line_index) { int lc = 0; int previous = 'n'; int ch; rewind(istream); while (line_index > 0 && (ch = fgetc(istream)) != EOF) { if (ch == 'n') { line_index--; } if (previous == 'n') { lc++; } previous = ch; } return lc; } void print_random_line(FILE *istream, int line_index) { printf("%8d: <", line_index + 1); Line_Count(istream, line_index); int ch; while ((ch = fgetc(istream)) != EOF && ch != 'n') { if (isprint(ch)) { putchar(ch); } } printf(">n"); } int main() { srand((unsigned) time(NULL)); FILE *istream = fopen("test.txt", "r"); assert(istream); int lc = Line_Count(istream, RAND_MAX); assert(lc && lc < RAND_MAX); for (int i = 0; i < 5; i++) { print_random_line(istream, rand() % lc); } fclose(istream); } 

    这是另一种仍然受RAND_MAX限制的解决方案,它不需要读取每条直到所选线路的线路。 我们的想法是使用一个二进制文件,以相同的字节数存储每个单词,因此可以使用fseek()fread()访问任何单词。 文件中的第一个条目是一个long值,用于存储文件中的单词数。 添加单词时,将更新此值。

    这是一个实现,它查找名为wordlist.txt的普通文本文件,每行有一个单词。 如果找到,程序将更新(或创建,如有必要)名为wordlist.fmt的文件。 更新函数从文本文件中读取每个单词,跳过空行,并以固定的字节数将其存储在二进制文件中。 读完所有单词后,单词计数会更新。 使用文本文件运行程序一次后,应删除文本文件,否则下一次运行将再次添加单词。 .fmt文件应该保留,如果要添加更多单词,只需将新文本文件放在包含可执行文件的目录中,然后再次运行它。

    打印五个随机单词的循环生成一个随机数,使用该数字移动到包含单词的文件位置,将该单词读入数组并打印出来。

     #include  #include  #include  #define RAW_WORDS "wordlist.txt" #define FMT_WORDS "wordlist.fmt" #define OFFSET_SZ (sizeof(long)) #define MAXWORD 30 void update_words(FILE *fp_fmt, FILE *fp_raw); void strip(char *str); int main(void) { FILE *raw_words, *formatted_words; char word[MAXWORD]; long wordcount; int i; int wpos; raw_words = fopen(RAW_WORDS, "r"); /* Try to open existing file for update, otherwise open new file */ if ((formatted_words = fopen(FMT_WORDS, "r+b")) == NULL){ if ((formatted_words = fopen(FMT_WORDS, "w+b")) == NULL) { fprintf(stderr, "Unable to open file %sn", FMT_WORDS); exit(EXIT_FAILURE); } else { // initialize file wordcount wordcount = 0L; fwrite(&wordcount, OFFSET_SZ, 1, formatted_words); fflush(formatted_words); } } /* Update FMT_WORDS file if RAW_WORDS is present */ if (raw_words != NULL) update_words(formatted_words, raw_words); /* Get 5 random words and print them */ srand((unsigned)time(NULL)); rewind(formatted_words); fread(&wordcount, OFFSET_SZ, 1, formatted_words); printf("Five random words from %s:n", FMT_WORDS); for (i = 0; i < 5; i++) { wpos = rand() % wordcount; fseek(formatted_words, wpos * MAXWORD + OFFSET_SZ, SEEK_SET); fread(word, MAXWORD, 1, formatted_words); puts(word); } if (raw_words && (fclose(raw_words) != 0)) fprintf(stderr, "Unable to close file %sn", RAW_WORDS); if (fclose(formatted_words) != 0) fprintf(stderr, "Unable to close file %sn", FMT_WORDS); return 0; } void update_words(FILE *fp_fmt, FILE *fp_raw) { char word[MAXWORD]; long wordcount; /* Read in wordcount and move to end of file */ rewind(fp_fmt); fread(&wordcount, OFFSET_SZ, 1, fp_fmt); fseek(fp_fmt, wordcount * MAXWORD, SEEK_CUR); /* Write formatted words, skipping blank lines */ while (fgets(word, MAXWORD, fp_raw) != NULL) { if (word[0] != 'n') { strip(word); if (fwrite(word, MAXWORD, 1, fp_fmt) != 1) { fprintf(stderr, "Error writing to %sn", FMT_WORDS); exit(EXIT_FAILURE); } ++wordcount; } } /* Update wordcount in file and flush output */ rewind(fp_fmt); fwrite(&wordcount, OFFSET_SZ, 1, fp_fmt); fflush(fp_fmt); } void strip(char *str) { while (*str != 'n' && *str != '') str++; *str = ''; } 

      以上就是c/c++开发分享从.txt文件中读取随机行相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。

      本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

      ctvol管理联系方式QQ:251552304

      本文章地址:https://www.ctvol.com/c-cdevelopment/519767.html

      (0)
      上一篇 2020年12月5日
      下一篇 2020年12月5日

      精彩推荐