C - 读取未知格式的输入

标签 c parsing input format

我有一个文本文件作为输入,其行数未知,格式半未知。一个例子是:

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/

相关文章:

c - 为什么链接到 FastCGI 库会导致段错误?

c - 复数数组的 FFT

python - pyparsing ParseException : Expected end of line -- general questions 问题

html - input[type=password] IOS 不渲染键盘(Safari+Chrome)

c - 如何读取目标文件的重定位记录

使用 C 编程使用 argc 和 argv 参数创建一个刽子手游戏程序

json - 获取此输出 json 的所有值

Python3,通过单击按钮从url下载文件

javascript - 需要从启用多选的 html 文件输入中删除特定文件

css - 从输入类中获取标签