Ошеломленный в поисках работающего с & amp; Метод c ++ для удаления возврата каретки (чтение файла .csv)

Я читаю строки файла .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.
]

Кто-нибудь, пожалуйста, скажите мне, как избежать этого неправильного поведения возврата каретки.

1

Решение

Вот как это сделать, используя 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, чтобы он использовался как символ конца строки. Это особенно полезно для разбора каждой прочитанной строки в виде списка через запятую.

1

Другие решения

Некоторое чтение строки 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));

и должен передать размер буфера не ноль в качестве второго аргумента:

2

Вот как легко это может быть, когда увеличение а также станд :: 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.
0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector