Как читать отформатированные данные в C ++?

Я отформатировал данные следующим образом:

Words          5
AnotherWord    4
SomeWord       6

Он находится в текстовом файле, и я использую ifstream для его чтения, но как мне отделить число от слова? Слово будет состоять только из алфавитов, и между словом и числом будут определенные пробелы или табуляции, не знаю, сколько.


person TheOnly92    schedule 24.08.2010    source источник
comment
Я НЕ ЗНАЮ, если между словом и числом есть пробелы или табуляторы, внутри слова не будет пробелов.   -  person TheOnly92    schedule 24.08.2010
comment
если формат вашего файла становится более сложным, вы можете попробовать регулярные выражения для каждой строки. Boost предоставляет для этого библиотеку.   -  person Tobias Langner    schedule 24.08.2010


Ответы (4)


Предполагая, что внутри «слова» не будет пробелов (тогда это будет не 1 слово), вот пример того, как читать до конца файла:

std::ifstream file("file.txt");
std::string str;
int i;

while(file >> str >> i)
    std::cout << str << ' ' << i << std::endl;
person Donotalo    schedule 24.08.2010
comment
Что, если табуляция разделяет слово и целое число? - person TheOnly92; 24.08.2010
comment
Круто, это то решение, которое я хотел. - person TheOnly92; 24.08.2010
comment
Большинство форматов позволяют правильно пометить пробелы в словах. Что касается Unix или версии CSV с разделителями-пробелами, это одно слово и \ so \ is \ this. - person Michael; 02.04.2016

Оператор >> переопределяется для std :: string и использует пробелы в качестве разделитель

so

ifstream f("file.txt");

string str;
int i;
while ( !f.eof() )
{
  f >> str;
  f >> i;
  // do work
}
person mmmmmm    schedule 24.08.2010
comment
Я добавил printf("%s=%d\n", str.c_str(), i); после // do work. Последняя строка печатается дважды. Используя MSVC9. - person Aoi Karasu; 24.08.2010
comment
@AOI Karasu - да, извините, я только читал в переменных, работающих - person mmmmmm; 24.08.2010
comment
используйте f как условие цикла вместо !f.eof() - person rubenvb; 24.08.2010

Для этого подходит sscanf:

#include <cstdio>
#include <cstdlib>

int main ()
{
  char sentence []="Words          5";
  char str [100];
  int i;

  sscanf (sentence,"%s %*s %d",str,&i);
  printf ("%s -> %d\n",str,i);

  return EXIT_SUCCESS;
}
person Stefan Steiger    schedule 19.10.2010

На самом деле это очень просто, вы можете найти ссылку здесь
Если вы используете табуляции в качестве разделителей, вы можете вместо этого использовать getline и установить разделить аргумент на '\ t'. Более длинный пример:

#include <vector>
#include <fstream>
#include <string>

struct Line {
    string text;
    int number;
};

int main(){
    std::ifstream is("myfile.txt");
    std::vector<Line> lines;
    while (is){
        Line line;
        std::getline(is, line.text, '\t');
        is >> line.number;
        if (is){
            lines.push_back(line);
        }
    }
    for (std::size_type i = 0 ; i < lines.size() ; ++i){
        std::cout << "Line " << i << " text:  \"" << lines[i].text 
                  << "\", number: " << lines[i].number << std::endl;
    }
}
person Default    schedule 24.08.2010
comment
@Donatalo: если включить ‹string›, да. Хотя вам нужно включить строку, если вы также хотите использовать getline, так что у вас есть действительная точка :) Отредактировал мой ответ - person Default; 24.08.2010
comment
Фактически это будет читать даже строки с пробелами (кроме '\t') в нем. Однако у меня есть несколько проблем с этим: 1. Вам нужно проверить is непосредственно перед тем, как нажимать на вектор. 2. Проверка ошибок перед циклом должна возвращать int (и в любом случае в этом нет необходимости). Предполагая, что вы их исправите, я проголосовал за ваш ответ, несмотря на них. - person sbi; 24.08.2010
comment
@sbi: спасибо, отредактировал. Думаю, именно там должен быть чек на is (чтобы убедиться, что номер можно прочитать). Некоторое время назад я работал с iostreams .. - person Default; 24.08.2010
comment
@Michael: Нет, это все еще неправильно. Что произойдет, если прочитать целое число не удастся? При потоковом вводе вы либо хотите проверять каждую операцию ввода, либо полагаетесь на то, что operator>>() не работает, когда поток находится в плохом состоянии, и проверяете после последнего ввода . - person sbi; 24.08.2010
comment
@sbi: вы удалили свой голос или кто-то другой проголосовал против меня? - person Default; 24.08.2010
comment
@Michael: Нет, я этого не делал, но кто-то отверг вас. (Вы должны увидеть это на вкладке «Репутация» на странице недавних действий.) Я думал, что здесь считается плохим голосовать против, не оставляя комментария относительно причин, но ... - person sbi; 24.08.2010
comment
@Michael: <sigh> Теперь у вас есть один ненужный тест. Если вы не против, я пойду туда и исправлю. Если вы не согласны, вы всегда можете изменить это позже, хорошо? - person sbi; 25.08.2010
comment
Хорошо, я также добавил несколько отсутствует std:: и строка заключена в оболочку, так что вам не нужно прокручивать, чтобы прочитать код. Надеюсь, с тобой все в порядке. Если нет, смело верните его обратно. Я не компилировал код, поэтому надеюсь, что он так хорош, как мне кажется ... - person sbi; 25.08.2010
comment
@sbi: извините :) хотя спасибо. один комментарий: если is в порядке в конце цикла, он снова проверяется в начале цикла (где мы должны знать, в порядке ли?), а также, что произойдет, если getline не удастся? Или нам не нужно это проверять? Кроме того, я согласен с вами насчет того, чтобы комментировать отрицательные голоса ... Я подумал, что это довольно хороший ответ :( возможно, они проголосуют за него сейчас, когда вы его исправили :) - person Default; 25.08.2010
comment
@Michael: Да, я полагаю, если вы выйдете из цикла из-за ошибки, вы можете вернуть его в бесконечный цикл. Как только is перейдет в плохое состояние, все дальнейшие операции ввода завершатся ошибкой. Таким образом, если std::getline() выйдет из строя, is >> line.number тоже выйдет из строя, и у вас все еще будет is в состоянии отказа. (Вот почему я написал, что вы полагаетесь на то, что operator>>() не работает, когда поток находится в плохом состоянии, и проверяете после последнего ввода там.) Это также причина, по которой вам не нужно проверять поток впереди. Если он не открывается, ввод не удастся, и вы выйдете из цикла с ошибкой. - person sbi; 25.08.2010
comment
@sbi. Это логично, хотя я никогда об этом не задумывался. Спасибо за урок :) - person Default; 25.08.2010