2015-07-08 4 views
0

Я написал это, чтобы разобрать файл с числами, где разделитель был просто пространством. Моя цель - прочитать каждый номер файла и сохранить его в соответствующем индексе матрицы A. Итак, первое прочитанное число должно перейти к A [0] [0], второе число - к A [0] [1] и так далее.Прочитать файл с разделителем пробела и точкой с запятой

#include <iostream> 
#include <string> 
#include <fstream> 

using namespace std; 

int main() { 
    const int N = 5, M = 5; 
    double A[N*M]; 
    string fname("test_problem.txt"); 
    ifstream file(fname.c_str()); 
    for (int r = 0; r < N; ++r) { 
     for (int c = 0; c < M; ++c) { 
      file >> *(A + N*c + r); 
     } 
    } 

    for (int r = 0; r < N; ++r) { 
     for (int c = 0; c < M; ++c) { 
      cout << *(A + N*c + r) << " "; 
     } 
     cout << "\n"; 
    } 
    cout << endl; 

    return 0; 
} 

Теперь я пытаюсь разобрать файл, как это:

1 ;2 ;3 ;4 ;5 
10 ;20 ;30 ;40 ;50 
0.1 ;0.2 ;0.3 ;0.4 ;0.5 
11 ;21 ;31 ;41 ;5 
1 ;2 ;3 ;4 ;534 

, но он будет печатать (при этом чтение) мусор. Что мне делать?


EDIT

Вот моя попытка в C, который также не:

FILE* fp = fopen("test_problem.txt", "r"); 
double v = -1.0; 
while (fscanf(fp, "%f ;", &v) == 1) { 
    std::cout << v << std::endl; 
} 

-1 всегда будет напечатано.

+0

Все '* (А + Н * С + г) 'может быть изменен в' A [N * с + г ] '. – timrau

+0

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

+0

timrau, правда, но это не должно быть проблемой. @RedRoboHood Я отредактировал с моей целью. Я думаю, что тестовый пример хорош, я хочу заполнить матрицу номерами файла. – gsamaras

ответ

1

Вы должны удалить точку с запятой перед преобразованием

std::string temp; 
file >> temp; 
std::replace(temp.begin(), temp.end(), ';', ' '); 
*(A + N*c + r) = std::stod(temp); 
+0

Спасибо. Вы знаете, что мне делать, если в последнем номере каждой строки есть точка с запятой? Например, первая строка будет выглядеть следующим образом: «1; 2; 3; 4; 5;» вместо этого «1; 2; 3; 4; 5». – gsamaras

+0

Код работает с точкой с запятой в конце также – hsarret

+0

Нет, я получаю 'terminate called после вызова экземпляра 'std :: invalid_argument' what(): stod' – gsamaras

2

проблема с вашим примером C:

warning: format ‘%f’ expects argument of type ‘float*’, but 
     argument 3 has type ‘double*’ [-Wformat=] 

Всегда и везде, включите предупреждения (-Wall -Wextra) и сделать больше проверки ошибок.

В любом случае, до fscanf в double вам необходимо %lf вместо %f.

+0

О, это имеет смысл. Да, вы правы, я просто сделал небольшой пример и не включил флаги. – gsamaras

2

Учитывая ваш входной формат ...

1 ;2 ;3 ;4 ;5 

... код ...

for (int c = 0; c < M; ++c) { 
    file >> *(A + N*c + r); 
} 

... будет "съедать" первое числовое значение, то дроссель на первом ; разделитель. Простейшие коррекции будет ...

char expected_semicolon; 

for (int c = 0; c < M; ++c) { 
    if (c) { 
     file >> expected_semicolon; 
     assert(expected_semicolon == ';'); // if care + #include <cassert> 
    } 
    file >> *(A + N*c + r); 
} 

По какому это стоит, чтобы добавить лучшую проверку ошибок, я хотел бы предложить ...

if (std::ifstream file(fname)) 
{ 
    ...use file stream... 
} 
else 
{ 
    std::cerr << "oops\n"; 
    throw or exit(1); 
} 

... в качестве общей практики открытие потока файлов.

Для цикла получения данных, используя поддержку макросов дать утверждение, как стиль хорошо работает с потоками:

#define CHECK(CONDITION, MESSAGE) \ 
    do { \ 
     if (!(CONDITION)) { \ 
      std::ostringstream oss; \ 
      oss << __FILE__ << ':' << __LINE __ \ 
       << " CHECK FAILED: " << #CONDITION \ 
       << "; " << MESSAGE; \ 
      throw std::runtime_error(oss.str()); \ 
    } while (false) 

... 

for (int c = 0; c < M; ++c) { 
    if (c) 
     CHECK(file >> expected_semicolon && 
       expected_semicolon == ';', 
       "values should be separated by semicolons"); 
    CHECK(file >> *(A + N*c + r), "expected a numeric value"); 
} 

Для этого конкретного входного разборе, для производственной системы вы можете использовать getline так вам может знать, где вы находитесь на входе ...

size_t lineNum = 0; 
std::string my_string; 
for (int r = 0; r < N; ++r) { 
    CHECK(getline(file, my_string), "unexpect EOF in input"); 
    ++lineNum; 
    std::istringstream iss(my_string); 
     for (int c = 0; c < M; ++c) { 
      if (c) 
       CHECK(file >> expected_semicolon && 
         expected_semicolon == ';', 
         "unexpected char '" << c 
         << "' when semicolon separator needed on line " 
         << lineNum); 
      CHECK(iss >> *(A + N*c + r), 
        "non numeric value encountered on line " << lineNum); 
     } 
    } 
} 
+2

Я согласен с Тони, однако утверждение запускается, потому что вам нужно 'assert (expected_semicolon == ';');', который должен быть частью тела оператора if. – gsamaras

+1

@gsamaras: damn ,,, Я часто называю такие переменные 'c' - думал изменить его, потому что ваш код уже использовал' c', но только в одном месте .... Хороший призыв к необходимости держать assert с потоковое тоже .... Приветствия. –

+0

Я вскочил и изменил его перед комментарием TonyD. Надеюсь, я не смутил вещи. Учитывая 9-минутную задержку, я предположил, что Тони ушел :-) ... и я не исправил его полностью! –

0

Почему бы вам не попробовать GetLine(), который принимает разделитель в качестве 3-го аргумента.

string buffer; 
for (int c = 0; c < M; ++c) { 
    getline(file, buffer, ';'); 
    stringstream tmp(buffer); 
    tmp>>*(A + N*c + r); 
} 

GetLine() не будет читать до следующего разделителя или перевода строки или конец файла

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