如何从列文件中有选择地绘制(在C / C ++中)

时间:2013-12-05 13:21:41

标签: c++ c plot ascii

我试图有选择地从一个包含列的文件中绘制一些数据,而不是.csv或.tsv 典型文件为http://pastebin.com/pgSjezdh

你可以看到最初有一些信息,当然应该以某种方式跳过。 然后有一些列,我想从中绘制一个列。例如,第一列是x,第四列是y。

这个想法是使用CERN的root,它使用C / C ++,所以理想情况下这应该在C / C ++中完成,以便root可以处理它。

除此之外,主要问题是以某种方式以两列格式获得所需数据,没有字符串。

最有效的方法是什么?

2 个答案:

答案 0 :(得分:1)

您可以使用名为cern.l:

的此Flex代码
%x _DATA_
%x _END_

%option noyywrap
%{
  #define NUMBER_OF_COLUMNS 6
  #define FILENAME_LENGTH 64

  // variables
  float data;
  int dataNumber;
  FILE *files[NUMBER_OF_COLUMNS];
  char fileNames[NUMBER_OF_COLUMNS] [FILENAME_LENGTH];

  // functions
%} 
NUMBER [0-9]*(\.[0-9]+)?(E(\+|-)[0-9][0-9])?

%% 
"-----------  ---------- ---------- ----------  ----------  ----------" {
            fprintf(stderr,"\nBEGIN DATA");
            BEGIN(_DATA_);
        }
<_DATA_>"-----" {
                    BEGIN(_END_);
         }
<_DATA_>{NUMBER} {
         data = atof(yytext);
         fprintf(files[dataNumber],"%f\n",data);
         dataNumber = (dataNumber+1)%NUMBER_OF_COLUMNS;
        }
<_DATA_>"----------" { 
      BEGIN(_END_);
      }
%%
int main(int argc, char* argv[])
{
  int i = 0;
  dataNumber = 0;
  for(i = 0; i < NUMBER_OF_COLUMNS; i++)
  {
    sprintf(fileNames[i],"/home/user/column%d.txt",i);
    files[i] = fopen(fileNames[i],"w");
  }
  yyin=fopen("/home/user/example.dat","r");

  yylex();
  for(i = 0; i < NUMBER_OF_COLUMNS; i++)
  {
    fclose(files[i]);
  }
  return 0;
}

您可以使用make cern.l进行编译。 在Linux下,它将生成二进制可执行文件cern。调用./cern它将生成包含数据的6个文件(名为column0.txt column1.txt等)。

如果您希望将此代码作为函数集成到C ++程序中,则只需使用flex cern.l进行编译即可。它将生成一个名为lex.yy.c的文件,其中包含C代码。然后,您可以使用函数名称将main重命名为lex.yy.c,例如int parse(float *column0, float *column1, float *column2, float *column3, float *column4, float *column5)并从程序中调用它。显然,在这种情况下,您应该先修改原始的flex代码,以便用数据填充6个浮点数组。

为何使用Flex?因为它生成了优化的扫描仪。如果您需要在很短的时间内解析大量数据,那么它非常有用。我还发现它比使用C语言手动创建FSM更简单。

答案 1 :(得分:1)

从您的描述和示例输入中不太清楚,但我假设数据列在第25行到第51行。看起来好像正上方的连字符行表示列。第一列以该行的第一个字符开头。 (上面有一个类似的表,有四列和一行,它是缩进的,应该可以跳过。)数据行由另一行连字符终止。

所以基本算法是:读取连字符行的所有内容,存储每个字段的列宽和起始点,然后读取后续数据,使用连字符中的信息剪切出所需的列,并在何时停止读取你会遇到下一行。

这可能是脚本可以轻松完成的事情。下面的独立C程序也是如此。您可以从命令行调用它:

./colcut data.txt 3 5 1

打印文件“data.txt”的第3,5和1列(自然计数,而不是从零开始)。可能缺少错误处理 - 例如,它不会检查列是否足够长 - 但它看起来很有用:

#include <stdlib.h>
#include <stdio.h>



#define die(x) do {                             \
        fprintf(stderr, "Fatal: %s\n", x);      \
        exit(1);                                \
    } while (0)

#define MAX 10
#define MAXLEN 500

typedef struct {            /* Text slice into a char buffer */
    const char *str;        /* start pointer */
    int len;                /* slice length */
} Slice;

int main(int argc, char *argv[])
{
    FILE *f;
    int index[MAX];         /* column index */
    int nindex = 0;         /* number of columns to write */
    Slice cols[MAX];        /* column substrings */
    int context = 0;        /* Are we scaning columns? */
    int i;

    if (argc < 3) die("Usage: col file columns ...");

    for (i = 2; i < argc; i++) {
        int n = atoi(argv[i]);

        if (n < 1 || n > MAX) die("Illegal index");
        index[nindex++] = n - 1;
    }

    f = fopen(argv[1], "r");
    if (f == NULL) die("Could not open file.");

    for (;;) {
        char line[MAXLEN];

        if (fgets(line, MAXLEN, f) == NULL) break;

        if (context) {
            if (line[0] == '-') break;
            for (i = 0; i < nindex; i++) {
                int j = index[i];

                printf("    %.*s", cols[j].len, cols[j].str);
            }
            putchar(10);
        }

        if (line[0] == '-') {
            const char *p = line;
            int n = 0;

            while (*p == '-' || *p == ' ') {
                cols[n].str = p;
                while (*p == '-') p++;
                cols[n].len = p- cols[n].str;
                while (*p == ' ') p++;
                if (++n == MAX) break;
            }

            for (i = 0; i < nindex; i++) {
                if (index[i] >= n) die("Columns index out of range");
            }
            context = 1;
        }
    } 
    fclose(f);   

    return 0;
}