我试图有选择地从一个包含列的文件中绘制一些数据,而不是.csv或.tsv 典型文件为http://pastebin.com/pgSjezdh。
你可以看到最初有一些信息,当然应该以某种方式跳过。 然后有一些列,我想从中绘制一个列。例如,第一列是x,第四列是y。
这个想法是使用CERN的root,它使用C / C ++,所以理想情况下这应该在C / C ++中完成,以便root可以处理它。
除此之外,主要问题是以某种方式以两列格式获得所需数据,没有字符串。
最有效的方法是什么?
答案 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;
}