Ответ 1
Вы можете прочитать номер, прежде чем использовать std::getline
, который читается из потока и хранится в std::string
. Что-то вроде этого:
int num;
string str;
while(cin>>num){
getline(cin,str);
}
У меня есть данные в следующем формате:
4:How do you do? 10:Happy birthday 1:Purple monkey dishwasher 200:The Ancestral Territorial Imperatives of the Trumpeter Swan
Число может быть от 1 до 999, а длина строки не более 255 символов. Я новичок в С++, и кажется, что несколько источников рекомендуют извлекать форматированные данные с помощью оператора stream >>
, но когда я хочу извлечь строку, она останавливается при первом символе пробела. Есть ли способ настроить поток, чтобы остановить синтаксический анализ строки только в новой строке или в конце файла? Я видел, что существует метод getline
для извлечения всей строки, но тогда мне все же придется разделить его вручную [с помощью find_first_of
], не так ли?
Есть ли простой способ проанализировать данные в этом формате, используя только STL?
Вы можете прочитать номер, прежде чем использовать std::getline
, который читается из потока и хранится в std::string
. Что-то вроде этого:
int num;
string str;
while(cin>>num){
getline(cin,str);
}
С++ String Toolkit Library (StrTk) имеет следующее решение вашей проблемы:
#include <string>
#include <deque>
#include "strtk.hpp"
int main()
{
struct line_type
{
unsigned int id;
std::string str;
};
std::deque<line_type> line_list;
const std::string file_name = "data.txt";
strtk::for_each_line(file_name,
[&line_list](const std::string& line)
{
line_type temp_line;
const bool result = strtk::parse(line,
":",
temp_line.id,
temp_line.str);
if (!result) return;
line_list.push_back(temp_line);
});
return 0;
}
Дополнительные примеры можно найти Здесь
Вам уже сообщили о std::getline
, но они не упомянули одну деталь, которую вы, вероятно, найдете полезной: когда вы вызываете getline
, вы также можете передать параметр, указывающий, какой символ обрабатывать как конец ввода. Чтобы прочитать номер, вы можете использовать:
std::string number;
std::string name;
std::getline(infile, number, ':');
std::getline(infile, name);
Это приведет к тому, что данные до: ':' в number
, отбросить ':' и прочитать остальную часть строки в name
.
Если вы хотите использовать >>
для чтения данных, вы можете сделать это тоже, но это немного сложнее и вникает в область стандартной библиотеки, которую большинство людей никогда не трогает. Поток связан с locale
, который используется для таких вещей, как номера форматирования и (что важно), определяющие, что представляет собой "пустое пространство". Вы можете определить свою собственную локаль, чтобы определить ":" как пробел, а пробел ("") - не пустое. Скажите потоку, чтобы использовать этот язык, и он позволит вам читать ваши данные напрямую.
#include <locale>
#include <vector>
struct colonsep: std::ctype<char> {
colonsep(): 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::mask());
rc[':'] = std::ctype_base::space;
rc['\n'] = std::ctype_base::space;
return &rc[0];
}
};
Теперь, чтобы использовать его, мы "заливаем" поток локалью:
#include <fstream>
#include <iterator>
#include <algorithm>
#include <iostream>
typedef std::pair<int, std::string> data;
namespace std {
std::istream &operator>>(std::istream &is, data &d) {
return is >> d.first >> d.second;
}
std::ostream &operator<<(std::ostream &os, data const &d) {
return os << d.first << ":" << d.second;
}
}
int main() {
std::ifstream infile("testfile.txt");
infile.imbue(std::locale(std::locale(), new colonsep));
std::vector<data> d;
std::copy(std::istream_iterator<data>(infile),
std::istream_iterator<data>(),
std::back_inserter(d));
// just for fun, sort the data to show we can manipulate it:
std::sort(d.begin(), d.end());
std::copy(d.begin(), d.end(), std::ostream_iterator<data>(std::cout, "\n"));
return 0;
}
Теперь вы знаете, почему эту часть библиотеки так пренебрегают. Теоретически, получение стандартной библиотеки для выполнения вашей работы для вас отлично - но на самом деле, в большинстве случаев легче выполнять эту работу самостоятельно.
int i;
char *string = (char*)malloc(256*sizeof(char)); //since max is 255 chars, and +1 for '\0'
scanf("%d:%[^\n]s",&i, string); //use %255[^\n]s for accepting 255 chars max irrespective of input size
printf("%s\n", string);
Его C и будет работать и на С++. scanf обеспечивает больше контроля, но без управления ошибками. Поэтому используйте с осторожностью:).
Просто прочитайте данные по строкам (целая строка) с помощью getline и проанализируйте его.
Для разбора используйте find_first_of()