英文:
Inconsistent output of class variables using std::cout
问题
It seems you want a translation of the provided code. Here is the translated code:
我是C++的新手,尝试将一些我之前用Python写的项目转换成C++来学习。我在使用std::cout时遇到了一些奇怪的行为,希望你能帮我解决。
**简要描述**
我有一个类(称为`CSVRow`,下面有详细信息),它存储了从包含银行对账单数据的CSV文件中读取和解析的数据。程序会遍历CSV文件,读取每一行,将其解析为`CSVRow`对象,并将这些对象保存到`std::vector<CSVRow> rows`中。所有这些都按预期运行。以下是该类的代码:
```c++
class CSVRow {
public:
// 构造函数
CSVRow(std::string& unsplit_row, const char& delim=',') {
std::vector<std::string> parsed_row = SplitRow(unsplit_row, delim);
date = parsed_row[0];
merchant = parsed_row[1];
charge_type = parsed_row[2];
amount = parsed_row[3];
payee = "NONE";
}
// 与问题无关的获取器和设置器方法
void printRow() {
// 将包括这个方法的两种实现,一个正常工作,另一个有问题,下面会列出
}
private:
std::string date;
std::string merchant;
std::string charge_type;
std::string amount;
std::string payee;
std::vector<std::string> SplitRow(std::string& unsplit_row, const char& delim) {
std::istringstream stream(unsplit_row);
std::string token;
std::vector<std::string> row;
while(getline(stream, token, delim)) {
row.push_back(token);
}
return row;
}
};
为了确保数据被正确解析,我编写了一个名为printRow()
的公共类方法,用作健全检查;我循环遍历存储在rows
中的行,并使用std::cout
将各个类变量的详细信息打印到终端上。
如果我在单独的std::cout
语句中打印出每个类变量的信息,那么这将正常工作,但如果我尝试在一行上包括所有内容,我会得到意外的输出。这让我相信我对std::cout
的工作原理有所误解,但阅读文档并没有解答我的问题。我以为可能是字符限制,但这个链接表明情况并非如此。
以下是我尝试过的两种printRow()
方法。
正常工作的代码和输出
代码
void printRow() {
std::cout << date << "\n";
std::cout << merchant << "\n";
std::cout << amount << "\n";
std::cout << payee << "\n";
std::cout << "***********" << "\n";
}
示例输出
***********
4/14/23
SQ *SIPPY CAFE
-6.99
NONE
***********
4/14/23
UBER EATS
-23.56
NONE
***********
这正是我所期望的。
有问题的代码和输出
代码
void printRow() {
std::cout << date << " , " << merchant << ", " << amount << ", " << payee << "\n";
std::cout << "***********" << "\n";
}
示例输出
, NONE3 , SQ *SIPPY CAFE, -6.99
***********
, NONE3 , UBER EATS, -23.56
***********
如你所见,日期除了最后一个字符外都没有打印出来,而前一行CSV中的收款人也包含在该行的输出中。这完全让我困惑不解,因为printRow()
函数是在单独的CSVRow
对象上调用的,不应该能访问到上一行的(私有)类变量。我相信我肯定漏掉了一些非常明显的东西,但真的很感激任何帮助我理解为什么会发生这种情况的帮助。
对于那些想知道的人,这是如何调用printRow()
函数的:
int main() {
std::filesystem::path file_loc { getInputCSV() };
std::unordered_map<std::string, std::string> payee_map { buildPayeeMap() };
std::vector<CSVRow> rows;
std::fstream file(file_loc);
std::string line;
while(getline(file, line)) {
if (line[0] == '4') { // 临时解决方案,将来会解决,但现在我只想要四月份的行。
CSVRow row = CSVRow(line);
row.setPayee(payee_map);
rows.push_back(row);
}
}
for (auto row : rows) {
row.printRow();
}
}
对于那些询问的人,以下是与上述CSV文件对应的两行:
4/14/23,SQ *SIPPY CAFE,DEBIT,-6.99
4/14/23,UBER EATS,DEBIT,-23.56
<details>
<summary>英文:</summary>
I'm new to C++ and am attempting to write some of my older Python projects into C++ as a way to learn. I'm running into strange behavior with std::cout that I'm hoping you can help me with.
**Brief Description**
I have a class (called `CSVRow`, details below) that stores data read in and parsed from a CSV file containing bank statement data. The program goes through the CSV file, reads each line, parses it into a `CSVRow` object, and saves those objects into `std::vector<CSVRow> rows`. All of this is working as intended. Here's the code for the class:
```c++
class CSVRow {
public:
// Constructor
CSVRow(std::string& unsplit_row, const char& delim=',') {
std::vector<std::string> parsed_row = SplitRow(unsplit_row, delim);
date = parsed_row[0];
merchant = parsed_row[1];
charge_type = parsed_row[2];
amount = parsed_row[3];
payee = "NONE";
}
// Getter and setter methods immaterial to the question
void printRow() {
// Will include the two implementations of this method, one working and the other broken, below
}
private:
std::string date;
std::string merchant;
std::string charge_type;
std::string amount;
std::string payee;
std::vector<std::string> SplitRow(std::string& unsplit_row, const char& delim) {
std::istringstream stream(unsplit_row);
std::string token;
std::vector<std::string> row;
while(getline(stream, token, delim)) {
row.push_back(token);
}
return row;
}
};
In order to check to make sure the data was parsed correctly, I wrote a public class method called printRow()
that I use as a sanity check; I loop through the rows stored in rows
and print out to the terminal, using std::cout
, the details of the various class class variables.
This works if I print out each class variable's information in its own std::cout
statement, but I get unexpected output if I try to include everything on one line. This has led to me to believe I'm misunderstanding something about how std::cout
works, but reading the documentation hasn't helped answer my question. I thought it might be a character limit, but this link indicates this is not the case.
Here are the two things I've tried for printRow()
.
Working Code and Output
Code
void printRow() {
std::cout << date << "\n";
std::cout << merchant << "\n";
std::cout << amount << "\n";
std::cout << payee << "\n";
std::cout << "***********" << "\n";
}
Sample Output
***********
4/14/23
SQ *SIPPY CAFE
-6.99
NONE
***********
4/14/23
UBER EATS
-23.56
NONE
***********
This is exactly what I'd expect.
Broken Code and Output
Code
void printRow() {
std::cout << date << " , " << merchant << ", " << amount << ", " << payee << "\n";
std::cout << "***********" << "\n";
}
Sample Output
, NONE3 , SQ *SIPPY CAFE, -6.99
***********
, NONE3 , UBER EATS, -23.56
***********
As you can see, the date isn't printing except for the last character, and the payee from the previous line of the CSV is included in the line's output. This completely boggles my mind, as the printRow()
function is being called on the individual CSVRow
object, which shouldn't have access to the previous row's (private) class variables. I'm sure I'm missing something very obvious, but would really appreciate any help trying to understand why this is happening.
For those of you wondering, this is how the printRow()
function is being called:
int main() {
std::filesystem::path file_loc { getInputCSV() };
std::unordered_map<std::string, std::string> payee_map { buildPayeeMap() };
std::vector<CSVRow> rows;
std::fstream file(file_loc);
std::string line;
while(getline(file, line)) {
if (line[0] == '4') { // hacky and to be fixed, but right now I only want lines from Apr.
CSVRow row = CSVRow(line);
row.setPayee(payee_map);
rows.push_back(row);
}
}
for (auto row : rows) {
row.printRow();
}
}
For those who have asked, here are the two rows from the CSV file that correspond to the above:
4/14/23,SQ *SIPPY CAFE,DEBIT,-6.99
4/14/23,UBER EATS,DEBIT,-23.56
答案1
得分: 0
感谢所有提供非常有帮助的解决方案 - 问题原来是在原始CSV文件的每一行末尾有一个\r字符,当解析每一行时,这个字符被包括在amount变量中。我的解决方案(我相信还有其他方法)是更新CSVRow的SplitRow()函数如下以删除回车符:
std::vector<std::string> SplitRow(std::string& unsplit_row, const char& delim) {
// 从行中删除任何回车符
unsplit_row.erase(std::remove(unsplit_row.begin(), unsplit_row.end(), '\r'), unsplit_row.end());
std::istringstream stream(unsplit_row);
std::string token;
std::vector<std::string> row;
while(getline(stream, token, delim)) {
row.push_back(token);
}
return row;
}
英文:
Thank you all for the very helpful solutions - the issue turned out to be a \r character at the end of each line in the original CSV file, which was getting included in the amount variable when each line was parsed. My solution (I'm sure there are others) was to update CSVRow's SplitRow() function as follows to remove carriage returns:
std::vector<std::string> SplitRow(std::string& unsplit_row, const char& delim) {
// remove any carriage returns from the row
unsplit_row.erase(std::remove(unsplit_row.begin(), unsplit_row.end(), '\r'), unsplit_row.end());
std::istringstream stream(unsplit_row);
std::string token;
std::vector<std::string> row;
while(getline(stream, token, delim)) {
row.push_back(token);
}
return row;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论