我正在尝试解析文本文件,并将每个不同的单词添加到哈希表中,其中单词为键,其频率为值。这个问题被证明是阅读部分:文件是一个非常大的“普通”文本文件,因为它有标点符号和特殊字符。我想把所有非字母字符chars视为字边界。我有一些基本的东西:
char buffer[128];
while(fscanf(fp, "%127[A-Za-z]%*c", buffer) == 1) {
printf("%s\n", buffer);
memset(buffer, 0, 128);
}
然而,每当它实际击中前面有空格的非字母字符时就会发出窒息(例如,“the,cat is(brown)”将被读作“cat was”)。我知道代码的问题是什么,但我不知道如何绕过它。我只是阅读整行并手动解析会更好吗?我正在尝试scanf
,因为我觉得这对于你可以用格式字符串做的迷你正则表达式是一个非常好的候选者。
答案 0 :(得分:4)
建议使用isalpha()
,fgetc()
和简单的状态机。
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
int AdamRead(FILE *inf, char *dest, size_t n) {
int ch;
do {
ch = fgetc(inf);
if (ch == EOF) return EOF;
} while (!isalpha(ch));
assert(n > 1);
n--; // save room for \0
while (n-- > 0) {
*dest++ = ch;
ch = fgetc(inf);
if (!isalpha(ch)) break;
}
ungetc(ch, inf); // Add this is something else may need to parse `inf`.
*dest = '\0';
return 1;
}
char buffer[128];
while(AdamRead(fp, buffer, sizeof buffer) == 1) {
printf("%s\n", buffer);
}
注意:如果您想使用"%127[A-Za-z]%*[^A-Za-z]"
路线,代码可能需要以一次性fscanf(fp, "*[^A-Za-z]");
开头才能处理前导非字母。
答案 1 :(得分:0)
除了评论中提到的方式之外还有另一种方式。我不知道它是否更好。您可以使用fgets
从文件中读取行,然后使用strtok_r
POSIX函数对行进行标记。这里,r
表示函数是可重入的,这使得它是线程安全的。但是,您必须知道一行可以在文件中拥有的最大长度。
#include <stdio.h>
#include <string.h>
#define MAX_LEN 100
// in main
char line[MAX_LEN];
char *token;
const char *delim = "!@#$%^&*"; // all special characters
char *saveptr; // for strtok_r
FILE *fp = fopen("myfile.txt", "r");
while(fgets(line, MAX_LEN, fp) != NULL) {
for(; ; line = NULL) {
token = strtok_r(line, delim, &saveptr);
if(token == NULL)
break;
else {
// token is a string.
// process it
}
}
}
fclose(fp);
strtok_r
修改了它的第一个参数line
,因此如果出于其他目的需要,您应该保留它的副本。