2016-10-03 2 views
1

Я пытаюсь написать код, который будет анализировать текстовый файл с разделителями табуляции, назначив каждую строку между вкладками заданному элементу структуры образца, которую я определил. Во входном файле первая строка будет иметь все идентификаторы классов (c_name), вторая строка будет иметь все идентификаторы образца (s_name), а остальные строки будут содержать данные.Анализ текстового файла с разделителями с табуляцией

Я знаю, что это будет немного сложнее, потому что первый столбец на самом деле просто содержит ярлыки, но я решил, что начну с попытки выяснить общую схему синтаксического анализа.

Я могу собрать, что, например, для идентификаторов классов, вероятно, я должен использовать fscanf в цикле for, чтобы добавить каждый идентификатор в поле класса данного образца, но я теряюсь в фактической реализации. Основываясь на одном сообщении, которое я видел, я думал, что могу что-то сделать в соответствии с использованием %[^\t]\t в fscanf, чтобы читать в массив все, что не является вкладкой до вкладки, но я не думаю, что у меня это совершенно правильно.

Любые предложения были бы весьма полезными.

#define LENGTH 30 
#define MAX_OBS 80000 

typedef struct 
{ 
    char c_name[LENGTH]; 
    char s_name[LENGTH]; 
    double value[MAX_OBS]; 
} 
sample; 

// I've already calculated the number of columns in the file 
sample sample[total_columns]; 
for (int i = 0; i < total_columns; i++) 
    { 
     fscanf(input, "%[^\t]\t", sample[i].s_name); 
    } 

Edit: Я пробовал несколько различных вариантов кода ниже ("% [^ \ т \ п \ г] \ т \ п \ г" или «% [^ \ т \ п \ r]% * 1 [\ t \ n \ r] "или"% [^ \ t \ n \ r] "), и все они, как правило, работают, за исключением того, что в зависимости от размера, который я выделяю для данных и как долго я повторяюсь, в какой-то момент он дает ошибку сегментации. В приведенном ниже коде немедленно возникает ошибка сегментации, но если я произвольно изменю total_columns в обоих местах на 3, он напечатает Case Case Case. Кажется, что это работает до 14, после чего вся сегрегация программная. Я довольно запутался в этом вопросе. Я также попробовал mallocing memory для массива выборочных данных, чтобы убедиться, что это проблема стека и кучи, но это, похоже, не помогает. Большое спасибо за Вашу помощь!

sample data[total_columns]; 
fseek(input, 0, SEEK_SET); 
for (int i = 0; i < total_columns; i++) 
{ 
    fscanf(input, "%[^\t\n\r]\t\n\r", data[i].s_name); 
    printf("%s\n", data[i].s_name); 
} 

Пример входного файла будет выглядеть следующим образом:

Class Case Case Case Case Case Case Case Case Case Case Case Case Case Case Control Control Control Control Control Control Control Control Control Control Control Control Control Control Control Control 
Subject G038 G144 G135 G161 G116 G165 G133 G069 G002 G059 G039 G026 G125 G149 G108 G121 G060 G140 G127 G113 G023 G147 G011 G019 G148 G132 G010 G142 G020 G021 
Data1 0.000741628 0.00308607 0.000267431 0.001418697 0.0.000761145 0.0008281 0.002426075 0.000236698 0.004924871 0.000722752 0.003758006 0.000104813 0.000986619 0.000121803 0.000666854 0 0.000171394 0.000877993 0.002717391 0.001336501 0.000812089 0.001448743 5.28E-05 0.001944298 0.000292529 0.000469631 0.001674047 0.000651526 0.000336615 
Data2 0.102002396 0.108035127 0.015052531 0.079923731 0.020643362 0.086480609 0.017907667 0.016279315 0.076263965 0.034876124 0.187481931 0.090615572 0.037460171 0.143326961 0.029628502 0.049487575 0.020175439 0.122975405 0.019754837 0.006702899 0.014033264 0.040024363 0.076610375 0.069287599 0.098896479 0.011813681 0.293331246 0.037558052 0.303052867 0.137591517 
Data2 0.218495065 0.242891829 0.23747851 0.101306336 0.309040188 0.237477347 0.293837554 0.34351816 0.217572429 0.168651691 0.179387106 0.166516699 0.099970652 0.181003474 0.076126675 0.10244981 0.449561404 0.139257863 0.127579104 0.355797101 0.354544105 0.262855651 0.10167146 0.186068602 0.316763006 0.187466247 0.05701315 0.123825467 0.064780343 0.069847682 
Data4 0.141137543 0.090948286 0.102502388 0.013063365 0.162060849 0.166292135 0.070215996 0.063535037 0.333743609 0.131011609 0.140936687 0.150108506 0.07812762 0.230704405 0.069792935 0.120770743 0.164473684 0.448110378 0.42599534 0.074094203 0.096525097 0.157661185 0.036737518 0.213931398 0.091119285 0.438073807 0.224921728 0.187034237 0.06611442 0.086005218 
Data5 0.003594044 0.003948354 0.008137536 0.001327901 0.002161974 0.003552012 0.002760334 0.001898667 0.001420186 0.003165988 0.001011853 0.001217382 0.000314439 0.004254794 0.000213155 0.003650147 0 0.002742309 0.002633978 0 0.002524503 0.002146234 0.001751465 0.006543536 0.003941146 0.00049505 0.00435191 0.001944054 0.001303053 0.004207692 
Data6 0.000285242 2.27E-05 0 1.13E-05 0.0002964 3.62E-05 0.000138017 0.000210963 0.000662753 0 0 0 0 4.11E-05 0 0 0 0 0.000101307 0 0 0 0 5.28E-05 0.00152391 0 0 0 0 0 
Data7 0.002624223 0.001134584 0.00095511 0.000419934 0.000401011 0.001739761 0.00272583 0.002566717 0.000520735 0.002311674 0.006287944 0 6.29E-05 0.000143882 3.05E-05 0.000491366 0 0 3.38E-05 0 0.001782002 0.000957104 0.002594763 0.000527704 0.000105097 0.001192619 3.13E-05 0 0.000744602 0.000252461 
Data8 0.392777683 0.383875286 0.451499522 0.684663315 0.387394299 0.357992026 0.488406597 0.423473155 0.27267563 0.47454646 0.331020526 0.484041709 0.735955056 0.338841956 0.781699147 0.625403622 0.313596491 0.270545891 0.379259109 0.498913043 0.372438372 0.446271644 0.606698813 0.305593668 0.360535996 0.29889739 0.328710081 0.521222594 0.419924299 0.584111756 

Edit: Я, кажется, установил ее, изменив определение MAX_OBS - довольно уверен, что у меня есть фундаментальное непонимание того, что это на самом деле означает. Я должен буду изучить это. Спасибо еще раз за помощь!

+1

ли компилировать? Использование 'sample' как имени типа, так и имени переменной приведет к путанице, даже если компилятор ее примет. –

+2

Является ли последнее поле в строке, разделенной вкладкой или новой линией? Если это новая строка, вам нужно принять это во внимание, не так ли? Вы можете рассматривать ''% [^ \ t \ n "]% * 1 [\ t \ n]" ', который ищет не-табуляции, не-новые строки, за которыми следует вкладка или новая строка (' * 'подавляет назначение) Вы должны проверить возвращаемое значение из 'fscanf()' и прекратить обработку, если результат не равен 1. Как и вы, вы не получаете никакой информации о символе разделителя, вы также можете назначить разделитель для дополнительной проверки. –

+0

ваши данные имеют три строки.Они разделены новой строкой, а не вкладкой, правильно? – BLUEPIXY

ответ

2

попробовать это:

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

#define LENGTH 30 
#define MAX_OBS 80000 

typedef struct{ 
    char c_name[LENGTH]; 
    char s_name[LENGTH]; 
    double value[MAX_OBS]; 
} Sample;//Duplication of type and variable names should be avoided. pointed out by Jonathan Leffler. 

int main(void){ 
    char line[1024]; 
    FILE *input = fopen("data.txt", "r"); 

    fgets(line, sizeof(line), input); 

    int total_columns = 0; 
    char *p = strtok(line, "\t\n"); 

    while(p){ 
     ++total_columns; 
     p = strtok(NULL, "\t\n"); 
    } 
    --total_columns;//first column is field name 
    rewind(input); 
//******************************************************************************* 
    Sample *sample = malloc(total_columns * sizeof(*sample));//To allocate in the stack is large. So allocate by malloc. 

    fscanf(input, "%*s\t");//skip first column 
    for (int i = 0; i < total_columns; i++){ 
     fscanf(input, "%[^\t\n]\t", sample[i].c_name);//\n for last column 
    } 
    fscanf(input, "%*s\t");//skip first column 
    for (int i = 0; i < total_columns; i++){ 
     fscanf(input, "%[^\t\n]\t", sample[i].s_name); 
    } 
    int r; 
    for(r = 0; r < MAX_OBS; ++r){ 
     if(EOF==fscanf(input, "%*s")) break; 
     for (int i = 0; i < total_columns; i++){ 
      fscanf(input, "%lf", &sample[i].value[r]); 
     } 
    } 
    fclose(input); 

    //test print 
    printf("%s\n", sample[0].c_name); 
    printf("%s\n", sample[0].s_name); 
    for(int i = 0; i < r; ++i) 
     printf("%f\n", sample[0].value[i]); 
    printf("\n%s\n", sample[total_columns-1].c_name); 
    printf("%s\n", sample[total_columns-1].s_name); 
    for(int i = 0; i < r; ++i) 
     printf("%f\n", sample[total_columns-1].value[i]); 
    free(sample); 
} 
+0

Вау - это супер полезно! Спасибо! Мне обязательно придется пройти через часть логики, но это действительно помогает. Один вопрос, который у меня есть, - это то, как/почему вы достигли 1024 для размера линейного массива? –

+0

@AllieH У него нет определенного основания, достаточно ли его длины. Я думаю, что вы используете 'getline' лучше, чем' fgets' Если максимальная длина не определена. – BLUEPIXY

+0

Удивительный! Еще раз спасибо. Это было невероятно полезно. –

Смежные вопросы