2014-09-28 2 views
0

Я пытаюсь прочитать текстовый файл, содержащий строку «a3rm5t? 7! Z * & gzt9v», и поместить все числовые символы в символьную строку для последующего преобразования в целое число ,Прочитать текстовый файл, сохранить все цифры в строку символов

В настоящее время я пытаюсь это сделать, используя sscanf в буфере после прочтения файла, а затем используя sprintf для сохранения всех символов, найденных с помощью% u в символьной строке str.

Однако целое число, возвращаемое при вызове printf на str, различно при каждом запуске программы. Что я делаю правильно и что я делаю неправильно?

Этот код работает, когда текстовый файл содержит строку типа «23dog» и возвращает 23, но не тогда, когда строка является чем-то вроде 23dog2.

EDIT: Теперь я понимаю, что я должен помещать числовые символы в символ ARRAY, а не только одну строку.

int main(int argc, const char **argv) 
{ 
    int in; 
    char buffer[128]; 
    char *str; 
    FILE *input; 

    in = open(argv[1], O_RDONLY); 
    read(in, buffer, 128); 

    unsigned x; 
    sscanf(buffer, "%u", &x); 
    sprintf(str,"%u\n", x); 
    printf("%s\n",str); 

    close (in); 

    exit(0); 
} 
+0

Отступ ваш код. – gsamaras

+0

в каком формате? – Broaj

+0

Если я не ошибаюсь, sprintf с% u заканчивает чтение ввода после первого нецифрового символа. Вы должны создать строку с номером перед преобразованием в целое число –

ответ

1

Если вы просто хотите, чтобы отфильтровать не-цифры от вашего входа, вам не нужно использовать scanf, sprintf и тому подобное. Просто переместите буфер и скопируйте символы, которые являются цифрами.

Следующая программа работает только для одной строки ввода, считанной со стандартного ввода, и только в том случае, если она имеет длину менее 512 символов, но она должна дать вам правильную идею.

#include <stdio.h> 

#define BUFFER_SIZE 512 

int 
main() 
{ 
    char buffer[BUFFER_SIZE]; /* Here we read into. */ 
    char digits[BUFFER_SIZE]; /* Here we insert the digits. */ 
    char * pos; 
    size_t i = 0; 
    /* Read one line of input (max BUFFER_SIZE - 1 characters). */ 
    if (!fgets(buffer, BUFFER_SIZE, stdin)) 
    { 
     perror("fgets"); 
     return 1; 
    } 
    /* Loop over the (NUL terminated) buffer. */ 
    for (pos = buffer; *pos; ++pos) 
    { 
     if (*pos >= '0' && *pos <= '9') 
     { 
      /* It's a digit: copy it over. */ 
      digits[i++] = *pos; 
     } 
    } 
    digits[i] = '\0'; /* NUL terminate the string. */ 
    printf("%s\n", digits); 
    return 0; 
} 
+0

Я пытаюсь понять код лучше, хотя я смог изменить его, чтобы принять текстовый файл. похоже, что мы устанавливаем pos равным буферу, затем перебираем буфер и, если следующий символ - это цифры, он указывает на массив цифр. I ++ в скобках сохраняют итерационные цифры до 1,2,3 и т. Д. Что именно делает нулевое завершение строки и fgets? – Broaj

+0

@Broaj Почти точно, за исключением того, что он, конечно, не «указывает на массив цифр», а скорее * скопирован * на него. NUL, завершающий строку, просто означает добавление в конец байта NUL, поэтому 'printf' знает, где заканчивается строка. 'fgets' считывает одну строку из файла и сохраняет ее в буфер (если буфер достаточно велик, иначе строка усекается). Дополнительную информацию см. В [man page] (http://linux.die.net/man/3/fgets). Использование 'fgets' здесь не является существенным, вы можете прочитать файл, но это наиболее удобно для вас. – 5gon12eder

0

Хороший подход к любой проблеме, как это читать всей линии в buffer, а затем назначить pointer к buffer. Затем вы можете использовать указатель, чтобы пройти через буфер, считывая каждый символ и действуя на него соответствующим образом. Ниже приведен пример такого подхода. getline используется для чтения строки из файла (у нее есть преимущество выделения пространства для buffer и возврата количества прочитанных символов). Затем вы выделяете пространство для символьной строки на основе размера буфера, возвращаемого getline. Помните, что когда вы закончите, вы несете ответственность за освобождение памяти, выделенной getline.

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

int main (int argc, const char **argv) 
{ 
    char *buffer = NULL; /* forces getline to allocate required space */ 
    ssize_t read = 0;  /* number of characters read by getline   */ 
    size_t n = 0;   /* limit of characters to read, (0 no limit) */ 
    char *str = NULL;  /* string to hold digits read from file   */ 
    char *p = NULL;   /* ptr to use with buffer (could use buffer) */ 
    int idx = 0;   /* index for adding digits to str    */ 
    int number = 0;   /* int to hold number parsed from file   */ 
    FILE *input; 

    /* validate input */ 
    if (argc < 2) { printf ("Error: insufficient input. Usage: %s filename\n", argv[0]); return 1; } 

    /* open and validate file */ 
    input = fopen(argv[1], "r"); 
    if (!input) { printf ("Error: failed to open file '%s\n", argv[1]); return 1; } 

    /* read line from file with getline */ 
    if ((read = getline (&buffer, &n, input)) != -1) 
    { 
     str = malloc (sizeof (char) * read); /* allocate memory for str  */ 
     p = buffer;        /* set pointer to buffer  */ 
     while (*p)        /* read each char in buffer  */ 
     { 
      if (*p > 0x2f && *p < 0x3a)   /* if char is digit 0-9   */ 
      { 
       str[idx] = *p;     /* copy to str at idx   */ 
       idx++;       /* increment idx    */ 
      } 
      p++;        /* increment pointer   */ 
     } 
     str[idx] = 0;       /* null-terminate str   */ 

     number = atoi (str);     /* convert str to int   */ 

     printf ("\n string : %s number : %d\n\n", buffer, number); 

    } else { 
     printf ("Error: nothing read from file '%s\n", argv[1]); 
     return 1; 
    } 

    if (input) fclose (input);     /* close input file stream   */ 
    if (buffer) free (buffer);     /* free memory allocated by getline */ 
    if (str) free (str);      /* free memory allocated to str  */ 

    return 0; 
} 

: Файл данных

$ cat dat/fwintstr.dat 
a3rm5t?7!z*&gzt9v 

выход:

$ ./bin/prsint dat/fwintstr.dat 

string : a3rm5t?7!z*&gzt9v 
number : 3579 
+0

Хорошая работа. Я хотел избежать распределения динамической памяти в своем ответе, поскольку она добавляет дополнительную сложность, и OP изначально также обошелся без него. Я должен сказать, что среди тестов 'c> 0x2f && c < 0x3a', 'c > = '0' && c <= '9'' и' isdigit (c) ', я считаю первое наименее читаемым. – 5gon12eder

+0

Другим фаворитом является 'c> '/' && c <':'' или 'c> 47 && c <58'. Цель состоит в том, чтобы избежать первоначального преобразования символов. Я также видел, что это выражалось как бит-сдвиги. Я согласен с тем, что читаемость является ключевой. Он должен быть правильно закодирован как 'c> = '0' && c <= '9''. Тем не менее, иногда, маленькие самородки обучения посыпаются, только для этой цели, а не случайно :) –