我有一个文本文件作为输入,其行数未知,格式半未知。一个例子是:
p1 a x1 300
p2 b x3 200 c x2 x1 500
p3 c x1 x3 1500 b x2 100 a x3 800
其中 'c' 操作涉及两个 'x' 对象,其他操作涉及一个对象。操作的顺序可以是随机的,操作的数量也是随机的。我需要存储'p'数字、操作类型、关联的'x'对象以及操作结束时的整数。
我不知道如何存储这些数据,因为 scanf()
仅适用于已知的格式化输入。我尝试使用 getc() 逐个字符地遍历每一行,但在尝试抓取和检查多个字符的同时,我无法以这种方式检测文件的结尾。
如果有人能帮助我找到一种存储这些数据的方法,我将不胜感激。
<小时/>编辑:
我的文本文件还有其他行,但最后一部分是我指定的。目前,这只抓取行中的第一个操作“n”次,其中“n”是行中操作的总数。
for (i = 0; i < lines; i++) {
if(fgets(line, MAXCHAR, fp)) {
if (line[0] == 'p' && isdigit(line[1])) { // Check if we are interested in parsing the line
k = opCount(line); // Amount of operations in line - Working
data[c_count].t_num = k;
data[c_count].trans = calloc(data[c_count].t_num, sizeof(clients));
for (j = 0; j < k; j++) {
tempBuf = strdup(line);
if(tempBuf) {
token = strtok(tempBuf, delim);
if(token) {
//1st of n sections = p1 a x1 300
token = strtok(NULL, " ");//parsing on space now
if(token) {
strcpy(data[c_count].trans[j].lineNum, token);
//2nd section is opType
token = strtok(NULL, " ");
if (token) {
data[c_count].trans[j].op_type = atoi(token);
token = strtok(NULL, " ");
if (token) {
data[c_count].trans[j].val = atoi(token);
}
}
}
}
}
free(tempBuf);
}
c_count++;
}
}
我也不确定这是否解释了“c”的情况,其中涉及两个对象......
最佳答案
...不知道如何将此数据存储为 scanf()...。
根据您在帖子中所描述的内容,您输入的语法实际上已经足够了解,可以解析它。以下是一些建议和一些可以帮助您入门的伪代码:
注意: scanf 并不是解析字符串的最佳选择,即使它们的语法具有一定的可预测性。我建议学习使用 fgets 与 strtok 结合使用(或 strtok_r)作为替代方案。
const char filespec[] = {"C:\\dev\\play\\data.txt"};
typedef struct { //container for operation/line
char lineNum[10];
char opType;
char op[2];
int val; //you did not describe this in question
}OP;
typedef struct { //container for each line
int opsCountOnLine;
OP *section;
}LINE;
const char *subs[] = {" a ", " b ", " c "};
int getLineCount(const char *filespec);//Counts '\n'. Adjust function if other criteria
int countOfOpsPerLine(const char line);//Counts occurances of 'a', 'b', 'c', ... on a line
int main(void)
{
int lineCount = getLineCount(filespec);
int i;
char line[280]; //adjust as necessary
FILE *fp = NULL;
LINE *lines = calloc(lineCount, sizeof(*lines));
if(lines)
{
fp = fopen(filespec, "r");
if(fp)
{
for(i=0;i<lineCount;i++)
{
if(fgets(line, 280, fp))
{
//here is where LINE can be populated with content of each line
//1. determine operations in 'line'.
lines[i].opsCountOnLine = countOfOpsPerLine(line);
//2. allocate memory for sections.
lines[i].section = calloc(lines[i].opsCountOnLine, sizeof(OP));
for(j=0;j<lines[i].opsCountOnLine;j++)
{
tempBuf = strdup(line);
if(tempBuf)
{
//SEE EDIT below for suggested content in this inner loop.
//3. Parse line into lines[i].section[0].line, lines[i].section[0].opType, etc.
// using delimiter of "abc" (...def...) with strtok()
//4. Other steps???
//then free tempBuf so you can use it again in the loop
free(tempBuf);
}
}
else
{
//notify user of error, exit
free(lines);
}
}
fclose(fp);
}
}
return 0;
}
int countOfOpsPerLine(const char *line) //Counts occurances of 'a', 'b', 'c', ... on a line
{
int count=0, i;
char *tok;
// Parse line to find number of sections
for(i=0;i<sizeof(subs)/sizeof(subs[0]);i++)
{
tok = strstr(line,subs[i]);
if(tok != NULL) count++;
}
return count;
}
int getLineCount(const char *filespec)
{
int c=0, count=0;
FILE *fp = fopen(filespec, "r");
if(fp)
{
for (c = getc(fp); c != EOF; c = getc(fp))
{
if (c == '\n') // Increment count if this character is newline
{
count = count + 1;
}
}
fclose(fp);
}
return count;
}
编辑以包含内部循环的建议(以及上面编辑的主结构) 由于您的输入文本似乎使用 a 或 b 或 c 作为 opType,因此您可以使用它们作为分隔符... 你可以使用
const char delim[] = {"abc"};
char *tok;
tok = strtok(tempBuf, delim);
if(tok)
{
//1st of n sections = p1 a x1 300
tok = strtok(NULL, " ");//parsing on space now
{
if(tok)
{
strcpy(lines[i].section[j].lineNum, tok);
//2nd section is opType
tok = strtok(NULL)
if(tok)
{
lines[i].section[j].opType = atoi(tok);
//3rd section is op (and so on...)
//repeat the same process here until you
//parsed and placed all members
}
}
}
}
关于C - 读取未知格式的输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59136682/