-2

我必须开发一个简单的解析器,例如读取“块”文本:

/TEST
 {. text .}
/TEST_DATA
 {. infs .}

而且,我需要阅读标签内部的信息......并且......具有这些信息的文件......有很多标签,具有相同的性能

例如:

/TEST
 {. text .}
/TEST_DATA
 {. infs .}

/LBL1
 {. text .}
/LBL1_DATA
 {. infs .}

/LBL2
 {. text .}
/LBL2_DATA
 {. infs .}

/LBL3
 {. text .}
/LBL3_DATA
 {. infs .}

我需要阅读特定标签块,例如:

parseFile("文件名.txt", LBL1)

和函数,为我返回块内的文本:LBL1 和 LBL1_DATA 或者,为我返回 LBL1 和 LBL1_DATA 的内容

我不知道,我该怎么做 :xxx 我需要帮助 ;x

谢谢。

4

3 回答 3

4

假设数据在一行,这是一个非常简单的代码示例。

你需要,显然测试它,测试它并测试它。查看您的行为,修复可能的错误和我忘记做的事情(现在这是您的工作),您的新实现也是如此。

int main(void)
{
    const char *key = "TEST";
    const char *filename = "file";

    char *val = get(filename, key);
    if(val) {
        printf("%s\n", val); // {. text .}
        free(val); // don't to forget!
    } else {
        printf("'%s' was not found.\n", key);
    }


}


char*
get(const char *filename, const char *key) {

    char *line = NULL, *pline = NULL, *buf = NULL, *pbuf, *tbuf;
    size_t size = -1, ssearch = strlen(key), i = 0, bufsize = 256;
    int open = 0;
    FILE *fp = fopen(filename, "r");

    if(fp == NULL) {
        fprintf(stderr, "Cannot read '%s' file.\n", filename);
        exit(EXIT_FAILURE);
    }

    while(getline(&line, &size, fp) != -1) {

        if(open == 0 && *line == '/' && 
           strncmp(line + 1, key, ssearch) == 0 && isspace(((unsigned char)*(line + ssearch + 1)))) {
            open = 1;
            continue;
        }

        if(open) {
            pline = line;

            while(isspace((unsigned char) *pline)) ++ pline; /* strip white-spaces [\r\n\t\v ] */

            if(*pline == '{') {
                if((buf = malloc(bufsize)) == NULL) {
                    fprintf(stderr, "NO MEMORY!");
                    exit(EXIT_FAILURE);
                }

                ++pline; /* strip '{' */

                pbuf = buf;
                while(1) {

                    if(*pline == '\0') {
                        fprintf(stderr, "EOF but '{' was not closed.");
                        exit(EXIT_FAILURE);
                    }

                    /* etc.. */

                    if(*pline == '}') break; 

                    if((i + size + 1) >= bufsize) {

                        if((tbuf = realloc(buf, bufsize + size + 1)) == NULL) {
                            if(buf) free(buf);
                            fprintf(stderr, "No MEMORY!\n");
                            exit(EXIT_FAILURE);
                        }

                        buf = tbuf;
                    }   

                    *pbuf ++= *pline++, 
                    i ++;
                }   

                *pbuf ++= '\0';

                if(pline != NULL) 
                    free(line);

                fclose(fp);

                return buf;

            } else {
                fprintf(stderr, "expected '{' but '%c' was found.\n", *pline);
                exit(EXIT_FAILURE);
            }
        }

        line = NULL;
        size = -1;
    }

    if(line != NULL)
        free(line);

    fclose(fp);


    return NULL;
}

更新:编写了更简单的代码。

#define EXPECTEDSYMBOL(w, f) \
        fprintf(stderr, "expected '%c' but '%c' was found.\n", w, f); \
        exit(EXIT_FAILURE)

char* get2(const char *filename, const char *key) {

    char *line = NULL, *buf = NULL, *pline;
    size_t size = -1, ssearch = strlen(key);
    int open = 0;
    FILE *fp = fopen(filename, "r");

    if(fp == NULL) {
        fprintf(stderr, "Cannot read '%s' file.\n", filename);
        exit(EXIT_FAILURE);
    }

    while(getline(&line, &size, fp) != -1) {

        if(open == 0 && *line == '/' && 
           strncmp(line + 1, key, ssearch) == 0 && isspace(((unsigned char)*(line + ssearch + 1)))) {
            open = 1;
            continue;
        }

        if(open) {

            pline = line;

            while(isspace((unsigned char) *pline)) ++ pline;

            if(*pline != '{') {
                EXPECTEDSYMBOL('{', *pline);
            } 

            if(strchr(pline, '}') == NULL) {
                EXPECTEDSYMBOL('}', *(pline + strlen(pline) - 1));
            }

            buf = pline;

            break;
        }

        line = NULL;
    }

    fclose(fp);


    return buf;

}

我希望这对你有帮助。

编辑#2:我再次阅读了您的问题,发现您也需要以下键。

试试这个:

void
get(const char *filename, const char *key, char buf[][512]) {

    char *line = NULL;
    size_t size = -1, ssearch = strlen(key);
    int open = 0;

    FILE *fp = fopen(filename, "r");

    if(fp == NULL) {
        fprintf(stderr, "Cannot read '%s' file.\n", filename);
        exit(EXIT_FAILURE);
    }

    while(getline(&line, &size, fp) != -1) {

        if(open == 0 && *line == '/' && 
           strncmp(line + 1, key, ssearch) == 0 && isspace(((unsigned char)*(line + ssearch + 1)))) {
            open = 1;
            continue;
        }

        if(open == 1) {
            strcpy(buf[0], line);
            ++ open;
            continue;
        }

        if((open + 1) == 3) {
            getline(&line, &size, fp);
            strcpy(buf[1], line);
            break;
        }
    }

    fclose(fp); 

}

进而:

const char *key = "TEST"; // /TEST
const char *filename = "config";
char buf[2][512] = { { 0 } };

get(filename, key, buf);
printf("%s\n", buf[0]); //  {. text . }
printf("%s\n", buf[1]); //  {. infs .}
于 2012-06-19T00:11:47.853 回答
1

你主要有两个选择:

  • 手动解析文件,通过将所有内容存储在运行时结构中并通过跳过标记解析字符串来解析数据(借助 stdio,例如fread,fscanffseek
  • 使用解析器生成器(flex + bison是您的首选):您将需要研究一下这些是如何工作的,但随后一切都会像魅力一样工作,而且它很容易维护,快速查看这里这里开始
于 2012-06-18T18:06:01.913 回答
0

我通常使用 awk 来处理文本。

$ awk '/^\/TEST$/, /}/{print $0}' test.dat | tail -1
 {. text .}

这告诉 awk 返回一系列行。返回的第一行将匹配这个正则表达式,^\/TEST$; 返回的最后一行将匹配这一行,}. 并且tail -1只将最后一行传递给标准输出。

如果“文本”实际上可以是多行文本,那么我可能会通过管道传递给 awk 而不是 tail。

$ awk '/^\/TEST$/, /}/{print $0}' test.dat | awk 'NR!=1{print $0}'
 {. text
text
text
.}

如果您愿意,可以将该单行代码重新打包为 shell 脚本。

于 2012-06-18T18:21:41.640 回答