Как элегантно читать целые числа, используя поток C ++? - PullRequest
8 голосов
/ 22 января 2011

У меня есть файл, полный строк в этом формате:

1 - 2: 3

Я хочу загружать только числа, используя потоки C ++. Какой самый элегантный способ сделать это? Я думал только о cin.get () и checikng каждого символа, если он номер или нет.

Ответы [ 6 ]

7 голосов
/ 22 января 2011

Я думаю, что это будет самый быстрый, но элегантный способ:

int a, b, c;
scanf("%d-%d:%d", &a, &b, &c);
6 голосов
/ 22 января 2011

Вы можете использовать locale , чтобы изменить то, что читается из файла во время его чтения. То есть вы отфильтруете все нечисловые значения:

struct numeric_only: std::ctype<char> 
{
    numeric_only(): std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table()
    {
        static std::vector<std::ctype_base::mask> 
            rc(std::ctype<char>::table_size,std::ctype_base::space);

        std::fill(&rc['0'], &rc[':'], std::ctype_base::digit);
        return &rc[0];
    }
};

std::fstream myFile("foo.txt");
myfile.imbue(std::locale(std::locale(), new numeric_only()));

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

std::vector<int> intFromFile;
std::istream_iterator<int> myFileIter(myFile);
std::istream_iterator<int> eos;
std::copy(myFileIter, eos, std::back_inserter(intFromFile));

Ответ на комментарии ниже:

Вот что я сделал, чтобы заставить его работать

int main(int args, char** argv){
    std::fstream blah;
    blah.open("foo.txt", std::fstream::in);
    if(!blah.is_open()){
        std::cout << "no file";
        return 0;
    }
    blah.imbue(std::locale(std::locale(), new numeric_only()));

    std::vector<int> intFromFile;
    std::istream_iterator<int> myFileIter(blah);
    std::istream_iterator<int> eos;
    std::copy(myFileIter, eos, std::back_inserter(intFromFile));

   return 0;
}

И это помещает в вектор только целые числа, ни больше, ни меньше. Причина, по которой он не работал раньше, была в два раза:

  1. Я заполнял до «9», но не до «9». Я изменил заливку на ':'
  2. Числа, превышающие то, что может хранить int, являются проблемой. Я бы предложил использовать длинные.
3 голосов
/ 22 января 2011

Я бы порекомендовал сделать по крайней мере краткий проверки работоспособности при чтении этого:

int a, b, c;
char dash, colon;

if (not (cin >> a >> dash >> b >> colon >> c) or dash != '-' or colon != ':')
    Failure. Do something.
1 голос
/ 22 января 2011

Извините, Конрад, но я рекомендую: никогда под страхом смерть , никогда никогда никогда (это достаточно ясно? -) читать отформатированные данные из файла. Просто не надо.

Существует только один правильный способ ввода форматированных данных: чтение фрагментов символов (обычно строк, но вы также можете читать блоки фиксированной длины).

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

Отдельный ввод (операция ввода / вывода) от разбора.

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

Я писал C ++ десятилетиями и никогда не читал целое число.

1 голос
/ 22 января 2011
    int a,b,c;

    cin >> a;
    cin.ignore(100,'-');
    cin >> b;
    cin.ignore(100,':');
    cin >> c;

    cout << "a = "<< a <<endl;
    cout << "b = "<< b <<endl;
    cout << "c = "<< c <<endl;

Ввод:

1 - 2: 3

Выход:

a = 1
b =2
c = 3

См. Здесь: http://www.ideone.com/DT9KJ

Примечание: это может также обрабатывать дополнительные пробелы.Таким образом, вы можете прочитать даже это:

 1     -        2      :      3

Подобная тема:

Использование ifstream в качестве fscanf

0 голосов
/ 22 января 2011

Просто,

ifstream file("file.txt");
int n1, n2, n3;
char tmp;
while (file.good()) {
  file >> n1 >> tmp >> n2 >> tmp >> n3;
}
...