В качестве примера использования предложенных ранее функций разбивки строки и конвертирования строки в число привожу листинг программы, которая читает данные из файла формата CSV в двумерный массив и выводит полученное на консоль.
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <iostream>
using std::string;
using std::vector;
using std::ifstream;
using std::istringstream;
using std::cout;
void splitString(const string &fullstr,
vector<string> &elements,
const string &delimiter) {
string::size_type lastpos =
fullstr.find_first_not_of(delimiter, 0);
string::size_type pos =
fullstr.find_first_of(delimiter, lastpos);
while ( (string::npos != pos) || (string::npos != lastpos) ) {
elements.push_back(fullstr.substr(lastpos, pos-lastpos));
lastpos = fullstr.find_first_not_of(delimiter, pos);
pos = fullstr.find_first_of(delimiter, lastpos);
}
}
double stringToDouble(const string &str) {
istringstream stm;
double val = 0;
stm.str(str);
stm >> val;
return val;
}
void readData(const string &filename,
const string &csvdelimiter,
vector< vector<double> > &sarr) {
ifstream fin(filename.c_str());
string s;
vector<string> selements;
vector<double> delements;
while ( !fin.eof() ) {
getline(fin, s);
if ( !s.empty() ) {
splitString(s, selements, csvdelimiter);
for ( size_t i=0; i<selements.size(); i++ ) {
delements.
push_back(stringToDouble(selements[i]));
}
sarr.push_back(delements);
selements.clear();
delements.clear();
}
}
fin.close();
}
int main(int argc, char** argv) {
vector< vector<double> > sarr;
readData("data.csv", ";", sarr);
for ( size_t i=0; i<sarr.size(); i++ ) {
for ( size_t j=0; j<sarr[0].size(); j++ ) {
cout << sarr[i][j] << "\t";
}
cout << "\n";
}
return 0;
}
Дабы не раздувать приведенный в качестве примера код, проверка доступности файла, возможности его открытия, а также однородности массива в файле с данными были опущены. Не забывайте о подобных проверках в реальных программах!
подправил маленький недочет
ОтветитьУдалитьЗдесь еще есть про двумерный массив:
ОтветитьУдалитьhttp://hashcode.ru/questions/57957
Подскажите пожалуйста! Есть csv файл вида:
ОтветитьУдалить"45.085","59.288","",""
"47.383","59.094","",""
Как сделать, чтобы программа пропускала еще и кавычки?
Что это за чудо программа сохраняет данные в таком формате? Первый раз вижу, чтобы числа в csv были обернуты в кавычки. Ну что ж... если необходимо обработать такое, то просто напишите функцию фильтр, которой будете передавать каждую считанную из файла строку. Т.е. считали из файла строку, передали функции. Функция прошлась посимвольно по строке, кавычки отбросила, новую строку без кавычек возвратила. Далее все как в примере. Самый простой вариант, если с ходу.
УдалитьЯ конвертирую координаты из Google Earth формата kml и получается такой файл, а кавычки ставятся исходя из описания формата csv: "Значения, содержащие зарезервированные символы (двойная кавычка, запятая, точка с запятой, новая строка) обрамляются двойными кавычками (")".
ОтветитьУдалитьСпасибо большое за помощь, вы направили мои мысли в нужную сторону!)
Пожалуйста. Рад был помочь.
УдалитьДобрый день! Спасибо большое за статью, очень помогла разобраться в вопросе.
ОтветитьУдалитьА как бы вы посоветовали поступить, если в csv файле не только числа, но и элементы с символами. Как раз о координатах опять идет речь, и зноке градусов. Ваш метод считывает только до знака градусов, и потом переходит к новому элементу.
Скажем, из строки
10127;8050;49°11'23.10"N,16°32'13.38"E
Считывает только 10127 8050 49
Я понимаю, что дело в функции stringToDouble, но не выходит ее переписать так, чтоб дальше все работало.
Буду благодарна за любой совет
Добрый день. Рад, что статья вам хотя бы частично, но уже помогла. В вашем случае я бы посоветовал поступить следующим образом. Во-первых, создайте класс, экземпляры которого будут хранить координаты. Со структурой класса, надеюсь, все понятно. Затем напишите функцию, которая будет распознавать данные с координатами. К примеру, считываете свою строку из файла, разбиваете по символу ";", каждый элемент прогоняете через функцию распознавания координат. Если функция возвращает true, то такой элемент скармливаете конструктору класса Coordinate (или как вы его там назовете), если false, то уже напрямую в функцию stringToDouble и складируете куда вам там нужно. Как-то так. Как реализовать функцию распознавания координат - ваш выбор. Можно, например, с помощью регулярных выражений.
УдалитьСпасибо за такой быстрый ответ :)
УдалитьА просто убрать stringToDouble и напрямую хранить стринг в элементах массива не сработает?
Прошу прощения, если вопрос глупый, это по сути моя первая программа в с++, и нужно все максимально просто сделать. Хотя то что вы выше предложили, конечно, звучит намного правильнее.
Пожалуйста, избавьтесь от подхода "сработает - не сработает". Это кривая дорожка ) Конечно можно хранить строки в векторе. Все зависит от вашей задачи, от ваших конечных целей. Если вам нужно будет делать еще какие-то вычисления - никуда не денешься, нужно конвертировать строки в числа, если же вы, к примеру, просто переводите из одного формата в другой, по сути задача считать файл и записать файл, то, разумеется, крутить данные из строки в число и обратно смысла нет никакого. Все зависит от вашей задачи.
УдалитьДа, вы правы, действительно нужно избавляться =)
ОтветитьУдалитьСпасибо за советы! Теперь я хотя бы точно знаю что мне нужно делать) Так как дальше мне полученные координаты нужно переводить в другой формат - таки буду делать по предложенному вами варианту.
И еще, если не сложно, намекните как с регулярными выражениями в данной ситуации работать) Я общую идею понимаю, что нужно ними описать структуру координат. Из-за отсутствия практики понять как реализовать трудно.
Регулярные выражения стали нам доступны в стандартной библиотеке с приходом C++11. Поэтому здесь важно каким компилятором и какой его версией вы пользуетесь. Если ваш компилятор не имеет реализации регулярных выражений в стандартной библиотеке - используйте boost.
УдалитьКак в данной ситуации работать с регулярными выражениями? Напрямую, непосредственно ) Если серьезно, то могу порекомендовать ресурс номер один для плюсовика (для начинающего программиста на С++ он должен стать лучшим другом) http://www.cplusplus.com. Уверен, что разберетесь. Вот страничка по регулярным выражениям http://www.cplusplus.com/reference/regex/. По каждой функции имеются примеры. Изучайте.
Если будете использовать библиотеки boost, то рекомендую сайт http://en.highscore.de/cpp/boost/. Здесь в подробностях рассказывается о различных компонентах этого замечательного набора библиотек, с примерами и комментариями. В частности, вот раздел по регулярным выражениям http://en.highscore.de/cpp/boost/stringhandling.html#stringhandling_regex.
Конечно, за вас я регулярное выражение для описания координат составлять не буду, иначе вы ничему не научитесь ) Еще полезно почитать чужой код, посмотреть как люди пишут. Загляните хотя бы в один из моих проектов. К примеру, здесь https://github.com/pa23/reup/blob/master/src/menu.cpp#L213 у меня используется регулярное выражение для поиска строк, содержащих имя файла вида P_986.2.0.0_YMZ-536_S3.14_15.05.2014.hex. Однако, имейте в виду, что здесь у меня используются так называемые "сырые" (raw) строки, опять же фишка из C++11. Если будете использовать обычные строки, то не забывайте экранировать все специальные символы.
ого, такой подробный ответ! Еще раз огромное спасибо =)
УдалитьТеперь полностью понятно направление, что читать и что делать.
Пожалуйста )
УдалитьА если у чисел в качестве разделителя разрядов используется запятая?
ОтветитьУдалитьТак замените запятую на точку )
Удалить...
#include
...
using std::replace;
...
double stringToDouble(const string &str) {
string tstr = str;
replace(tstr.begin(), tstr.end(), ',', '.');
istringstream stm;
double val = 0;
stm.str(tstr);
stm >> val;
return val;
}
...
Директивой include подключаем файл algorithm. Blogger подрезал текст из-за угловых скобок.
УдалитьСпасибо огромное за ваш пример! Не часто найдешь работающий понятный код без лишней воды. Стояла задача импортировать данные из очень объемного csv файла для последующей обработки. Благодаря вашему примеру быстро разобралась!
ОтветитьУдалитьПожалуйста. Очень рад, что пример полезен.
Удалить