在文本文件C中搜索字符串
以下代码一次读取一个字符的文本文件并将其打印到stdout:
#include int main() { char file_to_open[] = "text_file.txt", ch; FILE *file_ptr; if((file_ptr = fopen(file_to_open, "r")) != NULL) { while((ch = fgetc(file_ptr)) != EOF) { putchar(ch); } } else { printf("Could not open %s\n", file_to_open); return 1; } return(0); }
但是不是打印到stdout [putchar(ch)]而是我想在文件中搜索另一个文本文件中提供的特定字符串,即。 strings.txt并输出匹配到out.txt的行
text_file.txt
:
1993年 - 1999年奔腾 1997年 - 1999年Pentium II 1999年 - 2003年奔腾III 1998 - 2009 Xeon 2006 - 2009英特尔酷睿2
strings.txt
:
Nehalem处理器 AMD Athlon 奔腾
在这种情况下, text_file.txt
行将匹配。 我已经对C语言中的文件操作做了一些研究,似乎我可以用fgetc
读取一个字符[就像我在我的代码中一样],一行有fgets
,一行有fread
,但我猜不出来在我的情况下会是完美的吗?
我假设这是一个学习练习,你只是在寻找一个开始的地方。 否则,你不应该重新发明轮子。
下面的代码应该让您了解所涉及的内容。 它是一个程序,允许您指定要搜索的文件的名称以及在该文件中搜索的单个参数。 您应该能够修改此项以将短语设置为在字符串数组中搜索,并检查该数组中的任何单词是否出现在读取的任何行中。
您正在寻找的关键function是strstr
。
#include #include #include #ifdef DEBUG #define INITIAL_ALLOC 2 #else #define INITIAL_ALLOC 512 #endif char * read_line(FILE *fin) { char *buffer; char *tmp; int read_chars = 0; int bufsize = INITIAL_ALLOC; char *line = malloc(bufsize); if ( !line ) { return NULL; } buffer = line; while ( fgets(buffer, bufsize - read_chars, fin) ) { read_chars = strlen(line); if ( line[read_chars - 1] == '\n' ) { line[read_chars - 1] = '\0'; return line; } else { bufsize = 2 * bufsize; tmp = realloc(line, bufsize); if ( tmp ) { line = tmp; buffer = line + read_chars; } else { free(line); return NULL; } } } return NULL; } int main(int argc, char *argv[]) { FILE *fin; char *line; if ( argc != 3 ) { return EXIT_FAILURE; } fin = fopen(argv[1], "r"); if ( fin ) { while ( line = read_line(fin) ) { if ( strstr(line, argv[2]) ){ fprintf(stdout, "%s\n", line); } free(line); } } fclose(fin); return 0; }
样本输出:
E:\ Temp> searcher.exe searcher.c char char * char * buffer; char * tmp; int read_chars = 0; char * line = malloc(bufsize); while(fgets(buffer,bufsize - read_chars,fin)){ read_chars = strlen(line); if(line [read_chars - 1] =='\ n'){ line [read_chars - 1] ='\ 0'; buffer = line + read_chars; main(int argc,char * argv []){ char * line;
记住:fgetc(),getc(),getchar()都返回一个整数,而不是一个char。 整数可能是EOF或有效字符 – 但它返回的值多于char类型支持的范围。
你正在写’fgrep’命令的代理人:
fgrep -f strings.txt text_file.txt > out.txt
您不需要读取字符,而是需要读取行 – 使用fgets()。 (忘记gets()函数存在!)
我缩进你的代码并插入一个返回0; 最后为你(虽然C99隐含’返回0;’如果你从main()的末尾掉落)。 但是,C99还要求为每个函数提供一个显式的返回类型 – 我为你添加了’int’到’int main()’(但是你不能使用符合C99的理由来最后不返回0)。 错误消息应写入标准错误而不是标准输出。
您可能需要对字符串列表使用动态分配。 一个简单的搜索将简单地应用’strstr()’搜索每行输入中的每个必需字符串(确保一旦找到匹配就打破循环,这样如果有多个匹配则不重复一行在一条线上)。
更复杂的搜索将预先计算可以忽略哪些字符,以便您可以并行搜索所有字符串,比循环循环更快地跳过文本。 这可能是对Boyer-Moore或Knuth-Morris-Pratt等搜索算法的修改( 添加 :或者用于并行搜索多个字符串的Rabin-Karp)。
cat strings.txt |while read x; do grep "$x" text_file.txt; done
按块读取总是更好,因为它是底层文件系统的工作方式。
因此,只需按块读取,检查您的任何单词是否出现在缓冲区中,然后读取另一个缓冲区。 您只需要小心重新复制新缓冲区中前一个缓冲区的最后几个字符,以避免在搜索字位于缓冲区边界时丢失检测。
如果这个简单的算法不够(在你的情况下可能是这样),那么在Rabin-Karp中 ,有一个更复杂的算法可以同时搜索一个缓冲区中的几个子串。