【问题标题】:How to parse data between tags from a text file in C如何在C中的文本文件中解析标签之间的数据
【发布时间】:2015-11-04 13:40:51
【问题描述】:

我想使用 C 从文本文件中打印标签之间的数据。

输入语句: (PERSON) Mark Zuckerberg (/PERSON) 是来自 (LOCATION) USA (/LOCATION) 的企业家。他还是(组织)Facebook(/组织)的首席执行官。

输出:马克扎克伯格美国 Facebook。

我的程序代码是:

    const char* getfield(char* line, int num)
    {
        const char* tok;
        for (tok = strtok(line, "/>");
                tok && *tok;
                tok = strtok(NULL, "<\n"))
        {
            if (!--num)
                return tok;
        }
        return NULL;
    }

    int main()
    {
        char line[500000];
        while (fgets(line, 500000, stdin))
        {
            char* tmp = strdup(line);
            printf(" %s\n", getfield(tmp, 2));
            free(tmp);
        }
    }

它只打印马克扎克伯格。标签之间的其他数据没有显示?有人可以帮助我哪里出错了吗?我刚刚开始学习 C 中的文件处理,因此非常感谢您的指导。谢谢。

编辑:请将“(”替换为“”。

【问题讨论】:

  • 尝试先调试它...使用你最喜欢的调试器。
  • 我认为您的输入语句不包含任何标签(只有一个“>”)。请编辑问题以修正输入语句。
  • 0X0nosugar - 请检查编辑部分。
  • @Michael Walz 请检查编辑部分。
  • 顺便说一句,您可以将开始/结束标签放在代码块中:&lt;person&gt;Mark Z&lt;/person&gt;

标签: c parsing text tags


【解决方案1】:

我猜你的getfield 不会做你想做的事。在示例字符串(替换括号)上,您的 for 循环开始 strtok 将在第一个“>”处剪切(strtok 使用任何字符作为分隔符)所以第一个“PERSON”之后的那个。之后,您只在此标签的末尾剪切“>\n”。如果num 足够大,它会给出(在循环内):

<PERSON
 Mark Zuckerberg 
/PERSON> is a entrepreneur from 
LOCATION> USA 
/LOCATION>. He is also the CEO of 
ORGANIZATION> Facebook 
/ORGANIZATION>

您应该交替搜索:搜索结束标记 (>),然后搜索开始标记 (

char *gf(char *line, int num) {
  char *n1, *n2;
  // comments are for the 1st loop
  // search end of 1st tag (opening)
  n1 = strtok(line, ">\n");
  while(n1) {
    // search begin of 2nd tag (correp. closing)
    n2 = strtok(NULL, "<");
    // this one is good, shall we return it?
    if (num == 0) {
      return(n2);
    }
    printf("Found: %s\n", n2);
    // search end 2nd tag (have to skip it)
    n1 = strtok(NULL, ">\n");
    // search end of 3rd tag (opening), then loop (same situation)
    n1 = strtok(NULL, ">\n");
  }
  return NULL;
}

请注意,这段代码不是很好。如果你在常规文本中有“>”或“

注意之二:如果你需要一个健壮的方法,你将不得不读取标签。我的意思是找到一个标签(“”之间的东西),然后找到相应的结束标签(相同,但带有/和相同的内容),然后只获取里面的文本或产生错误。

编辑:我更改了函数,使其返回 numth 元素。您现在必须处理一个main() 函数,该函数能够多次调用此函数,num 的值不断增加,存储(或打印)结果,直到得到 NULL 答案。 作为家庭作业,您必须找到如何管理main 中的主字符串(行),以便可以进行连续调用(否则您实际上只会得到第一个标签):)

【讨论】:

  • 应用了你的方法,仍然在同一个位置。它仅读取第一个标签之间的数据,即仅打印 Mark Zuckerberg。请问同一个可以编辑代码吗?
  • 我认为你不理解我的代码。使用与您相同的输入,它将打印“Mark Zuckerberg”+“USA”+“Facebook”(真的在我的机器上进行了编码)。当然,这只是印刷品。如果您想要所有元素,请返回它们。在您的代码中,您似乎总是要求“2”nd 元素...
【解决方案2】:

您的fgets() 呼叫正在读取整行。然后调用getfield() 并打印结果。然后,您丢弃阅读的其余内容,尝试阅读更多内容,没有更多内容,然后退出循环。只要line 中有未处理的数据,就需要继续循环。

编辑:这里有一些示例代码可以帮助您入门:

int main()
{
    char line[500000];
    while (fgets(line, 500000, stdin))
    {
        char *arg = line;
        const char *tok;
        while ((tok = getfield(arg, 2)) != NULL) {
            printf("%s\n", tok);
            arg = NULL;
        }
    }
}

但请注意,这不是真正的解决方案。一方面,它会给你标签外的文本以及标签内的文本,所以你需要跳过它。另一方面,如果您的输入文件包含多行,它将无法真正正常工作。

【讨论】:

  • 怎么做?你能在代码中显示吗?我无法弄清楚这一点。
  • 您需要继续调用strtok,并以NULL 作为第一个参数,直到您消耗完整行。只有这样,您才应该读取新行并通过传递非NULL 第一个参数来重置strtok
  • 试过了。得到错误。请在代码中显示。我对此很陌生,无法弄清楚任何事情。
  • 见我上面的编辑。这只是一个示例,而不是真正的解决方案。您需要花一些时间自己弄清楚细节。
【解决方案3】:

编辑:在代码和解释中分别将 () 更改为 &lt;&gt;。谢谢汤姆。

这里是解决方案。尝试理解代码。此外,请随时根据您的需要对其进行修改。基本上,您需要做的是通过扫描字符&lt;&gt; 来扫描标签&lt;&gt; 或/和&lt;/&gt;。当你遇到&lt; 字符时,增加索引直到遇到&gt; 字符。一旦遇到&gt; 字符,然后开始复制&gt; 字符后面的字符,直到遇到另一个&lt; 字符,然后重复处理直到到达空终止字符'\0'

#include<stdio.h>
//#pragma warning(disable : 4996)

void removeTags(char inpData[], int dataLen);

int main()
{
   char letter, fileData[400];
   int numLetters;
   FILE *pfile;
   pfile = fopen("test.txt", "r");

   if (pfile == NULL)
   {
     printf("Error!Can not open file");
   }
   else 
   {
    numLetters = 0;
    while ((letter = fgetc(pfile)) != EOF) 
    {
        fileData[numLetters] = letter;
        numLetters++;
    }
    fileData[numLetters] = '\0';
    printf("File Data:\n\n");
    printf("%s", fileData);
    printf("\nRemoving Tags.....\n");
    removeTags(fileData,numLetters);
}

return 0;
}

void removeTags(char inpData[],int inpLen)
{
   char character,temp[400];
   int index = 0,tindex=0;

   while (inpData[index] != '\0')
   {
      if ((inpData[index] >= 'A' && inpData[index] <= 'Z') || (inpData[index] >= 'a' && inpData[index] <= 'z') || inpData[index] == ' ' || inpData[index] == '.')
      {
        temp[tindex] = inpData[index];
        index++;
        tindex++;
      }
      else if (inpData[index] == '<')
      {
        while (inpData[index] != '>')
        {
            index++;
        }
        index++;
        temp[tindex] = ' ';
        if (tindex > 0)
        {
            tindex++;
        }

    }
    else
    {
        break;
    }
}
temp[tindex] = '\0';
printf("%s", temp);
}

【讨论】:

  • 标签应该是标准的 XML 标签,用尖括号而不是圆括号分隔。帖子底部的编辑解释了这一点。
  • 糟糕!抱歉没有看到会编辑代码。无论如何,感谢 Tom Karzes 指出这一点。
  • 很高兴从字面上回答这个问题,但我真的不明白为什么顶级测试是必要的。除了不必要之外,它还会中断 all 提供的列表以外的其他字符。 &lt;..&gt; 可以简单地向上移动,作为唯一必要的测试。如果缺少&gt;,它可能会受益于行尾检查。
猜你喜欢
  • 1970-01-01
  • 2013-07-02
  • 1970-01-01
  • 1970-01-01
  • 2021-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多