Я читаю строки файла .csv через:
vector <string> vec_str;
char line[40];
while (1) {
memset (line, 0, 40 * sizeof (char));
if (fgets (line, 0, f_str_csv) == NULL) {
break;
}
//and then making strings out of NL trimmed line, and storing them in vec_str as
vec_str.push_back (string (line, strlen (line)).substr (0, strlen (line) - 1));
}
Кажется, я не могу избавиться от возврата каретки в конце line
читать из файла CSV.
Это становится очевидным, когда я анализирую строку через strtok
а также sscanf
с помощью:
vector <string>::iterator vec_str_it = vec_str.begin ();
strncpy (line, (*vec_str_it).c_str (), (*vec_str_it).length ());
char *buffer = NULL;
int data[2], i = 0;
char str[10];
buffer = strtok (line, ",");
while (buffer != NULL) {
cout << "[" << buffer << "]" << endl;
if (i == 2)
sscanf (buffer, "%s", str);
else
sscanf (buffer, "%d", &data[i]);
buffer = NULL;
buffer = strtok (NULL, ",");
i++;
}
дает мне вывод:
[10]
[20]
[James K.
]
для ввода 10,20,James K.
это строка, которую я прочитал из файла CSV.
Что здесь происходит не так?
Редактировать:
Также для более поздних файлов, если в конце строки встречается меньшее имя, например 11,31,Wu S.
после James K.
линия, я получаю остатки James K.
в buffer
после 2-й итерации, как видно из результата, как:
[11]
[31]
[Wu S.
K.
]
Кто-нибудь, пожалуйста, скажите мне, как избежать этого неправильного поведения возврата каретки.
Вот как это сделать, используя std :: getline и std :: ifstream:
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#include <sstream>
#include <vector>
class line {
public:
operator std::string() const {
return data_;
}
friend std::ostream& operator<<(std::ostream& out, const line& self) {
out << self.data_ << std::endl;
return out;
}
friend std::istream& operator>>(std::istream& in, line& self) {
std::getline(in, self.data_);
return in;
}
private:
std::string data_;
};
class csv_part {
public:
operator std::string() const {
return data_;
}
friend std::ostream& operator<<(std::ostream& out, const csv_part& self) {
out << self.data_;
return out;
}
friend std::istream& operator>>(std::istream& in, csv_part& self) {
std::getline(in, self.data_, ',');
return in;
}
private:
std::string data_;
};
int main() {
std::ifstream f_str_csv("myfile.csv");
if(f_str_csv.is_open()) {
std::vector<std::string> vec_str;
// Read all lines from file
std::copy(std::istream_iterator<line>(f_str_csv),
std::istream_iterator<line>(),
std::back_inserter(vec_str));
// loop through all lines read
for(std::vector<std::string>::const_iterator it = vec_str.begin();
it != vec_str.end();
++it) {
std::istringstream is(*it);
// Print every part of the line (separated with a comma),
// separated with a pipe symbol (|)
std::copy(std::istream_iterator<csv_part>(is),
std::istream_iterator<csv_part>(),
std::ostream_iterator<csv_part>(std::cout, "|"));
std::cout << std::endl;
}
} else {
std::cerr << "Could not open input file" << std::endl;
}
}
Обратите внимание, как вы можете указать аргумент std :: getline, чтобы он использовался как символ конца строки. Это особенно полезно для разбора каждой прочитанной строки в виде списка через запятую.
Некоторое чтение строки CSV, которое может содержать \ r и / или \ n и конец строки с использованием C / FILE:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
int main()
{
FILE* f_str_csv = stdin;
std::vector<std::string> vec_str;
const unsigned Length = 4096;
char line[Length];
while (std::fgets(line, Length, f_str_csv) != NULL) {
std::size_t n = std::strlen(line);
if(n) {
if(n + 1 == Length) {
// Overflow
throw std::overflow_error("Overflow");
}
switch(line[n-1]) {
case '\n':
case '\r':
if(--n) {
switch(line[n-1]) {
case '\n':
case '\r':
--n;
}
}
}
if(n) {
char* ln = line;
switch(ln[0]) {
case '\n':
case '\r':
++ln;
--n;
}
if(n) {
vec_str.push_back (std::string (ln, ln + n));
}
}
}
}
for(unsigned i = 0; i < vec_str.size(); ++i)
std::cout << vec_str[i] << '\n';
}
С man-страницы для fgets:
fgets () читает не более одного символа размером меньше из потока и
сохраняет их в буфер, на который указывает s. Чтение останавливается после
EOF или перевод строки. Если читается новая строка, она сохраняется в буфере. Завершающий нулевой байт (‘\ 0’) сохраняется после последнего
персонаж
в буфере.
Следовательно, вы можете пропустить
memset (строка, 0, 40 * sizeof (char));
и должен передать размер буфера не ноль в качестве второго аргумента:
Вот как легко это может быть, когда увеличение а также станд :: GetLine используются:
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
#include <boost/algorithm/string.hpp>
int main(int argc, const char *argv[])
{
std::fstream file;
file.open("input.txt");
std::vector<std::vector<std::string>> lines;
while (!file.eof()) {
std::string line;
// Read a line in the file to replace your C code.
std::getline(file, line);
std::vector<std::string> words;
// Split the words in the line - "\t ," defines the set of delimiters.
boost::split(words, line, boost::is_any_of("\t ,"));
lines.push_back(words);
}
// Oputput each word, you can also replace the range based loops if you don't
// use C++11.
for (const auto& line : lines)
{
for (const auto& word : line)
{
std::cout << word << " ";
}
std::cout << std::endl;
}
file.close();
return 0;
}
А для данных, которые вы хотите использовать, хранятся в текстовом файле «input.txt»:
11,31,James K.
11,31,Wu S.
Компиляция программы с g++ -std=c++11 main.cpp -o main
и выполнение его приводит к:
11 31 James K.
11 31 Wu S.