2010-06-10 2 views
1

Это классическая проблема, но я не могу найти простого решения.Разбор строк целых чисел в C

У меня есть входной файл, как:

1 3 9 13 23 25 34 36 38 40 52 54 59 
2 3 9 14 23 26 34 36 39 40 52 55 59 63 67 76 85 86 90 93 99 108 114 
2 4 9 15 23 27 34 36 63 67 76 85 86 90 93 99 108 115 
1 25 34 36 38 41 52 54 59 63 67 76 85 86 90 93 98 107 113 
2 3 9 16 24 28 
2 3 10 14 23 26 34 36 39 41 52 55 59 63 67 76 

линий различного количества целых чисел, разделенных пробелом.

Я хотел бы проанализировать их в массиве и отделить каждую строку маркером, допустим, -1.

Сложность в том, что я должен обрабатывать целые числа и строки.

Здесь мой существующий код, он петли на петлю scanf (поскольку scanf не может начинаться с заданной позиции).

#include <stdio.h> 
#include <stdlib.h> 
int main(int argc, char **argv) { 

    if (argc != 4) { 
    fprintf(stderr, "Usage: %s <data file> <nb transactions> <nb items>\n", argv[0]); 
    return 1; 
    } 
    FILE * file; 
    file = fopen (argv[1],"r"); 
    if (file==NULL) { 
    fprintf(stderr, "Error: can not open %s\n", argv[1]); 
    fclose(file); 
    return 1; 
    } 
    int nb_trans = atoi(argv[2]); 
    int nb_items = atoi(argv[3]); 
    int *bdd = malloc(sizeof(int) * (nb_trans + nb_items)); 
    char line[1024]; 
    int i = 0; 

    while (fgets(line, 1024, file)) { 
    int item; 
    while (sscanf (line, "%d ", &item)){ 
     printf("%s %d %d\n", line, i, item); 
     bdd[i++] = item; 
    } 
    bdd[i++] = -1; 
    } 

    for (i = 0; i < nb_trans + nb_items; i++) { 
    printf("%d ", bdd[i]); 
    } 
    printf("\n"); 
} 
+0

Почему бы не использовать многомерный массив? –

+0

Пожалуйста, пожалуйста, прекратите использование atoi() прямо сейчас. Да прямо сейчас. Измените каждый вызов atoi() на strtol() и скажите пятнадцать ошибок града, используя радиальные бусины. –

+0

@ Подумайте, если вы собираетесь предложить совет, по крайней мере, поддержите его. В противном случае, это просто какой-то случайный Джо в интернете :-) – paxdiablo

ответ

4

У вас есть несколько вариантов, открытых для вас, но это в общем, как я бы напасть на него:

Чтение во входном файле в виде текстового файла - это как набор строк - с fgets (). Это будет считаться до тех пор, пока не будет разорвана линия или EOF. Используйте функцию токенинга строки, которая проверяет каждую строку, прочитанную для пробелов, и возвращает подстроку перед пробелом. Теперь у вас есть строковое представление целого числа. Разберите это в фактический int, если хотите, или сохраните подстроку в своем массиве. Если вы переключите его на int, вы должны остерегаться переполнения, если он становится слишком большим.

+0

Это кажется немного более эффективным, чем мой ответ. Ах, хорошо, прошло какое-то время, так как я на самом деле использовал C. Я должен практиковать с ним больше. – JAB

+0

Для меня это было какое-то время, но мне не нужно было часто использовать материал в C++, но все это все еще довольно свежо для меня. Спасибо за комментарий. –

1

Читайте на входе в виде строки, сделать поиск для новой строки, создать новую строку с -1, где символ новой строки будет, и повторять это до тех пор, все новые строки не будут заменены на -1. Пока вы это делаете, вы также можете подсчитать количество пробелов, чтобы вы знали, как велико объявление вашего массива. (Вероятно, вы должны это сделать после замены новых строк.)

Затем создайте свой массив.

Далее, используйте sscanf или что-то для интерпретации целых чисел из строки в цикле и добавьте их в массив в нужном месте, пока не будут интерпретированы все целые числа (включая -1s).

РЕДАКТИРОВАТЬ: ... И это похоже на то, что вы делаете уже, по коду, который вы добавили к своему вопросу, когда я печатал свой ответ.

0

OK Я нашел решение, извините за шум, я должен найти больше ...

reading unknown number of integers from stdin (C)

Вместо моего цикла Scanf, используйте этот один:

while (fgets(line, 1024, file)) { 
    int item; 
    for (p = line; ; p = e) { 
     item = strtol(p, &e, 10); 
     if (p == e) 
      break; 
     bdd[i++] = item; 
    } 
    bdd[i++] = -1; 
    } 
+0

Lol, очень похоже на мое предложение :) –

+0

Это. Основная информация в этом решении - это функция strtol, которая возвращает вам конечный указатель поиска. –

+0

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

0

Вот полную программу на C, которая показывает, как вы можете это сделать. Он в основном читает строки одновременно с fgets, затем использует sscanf для обработки каждого из inetegrs на этой линии.

У этого есть рудиментарная проверка ошибок, но он не был протестирован с плохими данными (строка без цифр), но это должно быть хорошим началом.Просто замените printf заявления с кодом, который будет приобщать каждое число в массив:

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

int main (void) { 
    char line[1000]; 
    FILE *fIn; 
    char *str; 
    int val, num; 

    // Open input file and process line by line. 

    if ((fIn = fopen ("infile.txt", "r")) == NULL) { 
     fprintf (stderr, "Cannot open infile.txt, errno = %d\n", errno); 
     return 1; 
    } 

    while (fgets (line, sizeof (line), fIn) != NULL) { 
     // Check if line was too long. 

     if (line[strlen (line) - 1] != '\n') { 
      fprintf (stderr, "Line too long: [%s...]\n", line); 
      fclose (fIn); 
      return 1; 
     } 

     // Oyput the line and start processing it. 

     printf ("%s ", line); 
     str = line; 

     // Skip white space and scan first inetegr. 

     while (*str == ' ') str++; 

     num = sscanf (str, "%d", &val); 

     // Process the integer if it was there. 

     while ((num != 0) && (num != EOF)) { 
      // Print it out then skip to next. 

      printf ("[%d] ", val); 
      while ((*str != ' ') && (*str != '\0')) str++; 
      while (*str == ' ') str++; 
      num = sscanf (str, "%d", &val); 
     } 

     // -1 for line separator. 

     printf ("[%d]\n", -1); 
    } 

    // Close input file and exit. 

    fclose (fIn); 

    return 0; 
} 

А вот выход, чтобы показать вам, что это работает:

1 3 9 13 23 25 34 36 38 40 52 54 59 
    [1] [3] [9] [13] [23] [25] [34] [36] [38] [40] [52] [54] [59] [-1] 
2 3 9 14 23 26 34 36 39 40 52 55 59 63 67 76 85 86 90 93 99 108 114 
    [2] [3] [9] [14] [23] [26] [34] [36] [39] [40] [52] [55] [59] [63] [67] [76] [85] [86] [90] [93] [99] [108] [114] [-1] 
2 4 9 15 23 27 34 36 63 67 76 85 86 90 93 99 108 115 
    [2] [4] [9] [15] [23] [27] [34] [36] [63] [67] [76] [85] [86] [90] [93] [99] [108] [115] [-1] 
1 25 34 36 38 41 52 54 59 63 67 76 85 86 90 93 98 107 113 
    [1] [25] [34] [36] [38] [41] [52] [54] [59] [63] [67] [76] [85] [86] [90] [93] [98] [107] [113] [-1] 
2 3 9 16 24 28 
    [2] [3] [9] [16] [24] [28] [-1] 
2 3 10 14 23 26 34 36 39 41 52 55 59 63 67 76 
    [2] [3] [10] [14] [23] [26] [34] [36] [39] [41] [52] [55] [59] [63] [67] [76] [-1]