不规则输出类变量使用 std::cout

huangapple go评论59阅读模式
英文:

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&#39;m new to C++ and am attempting to write some of my older Python projects into C++ as a way to learn. I&#39;m running into strange behavior with std::cout that I&#39;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&lt;CSVRow&gt; rows`. All of this is working as intended. Here&#39;s the code for the class:


```c++
class CSVRow {
    public:
        // Constructor
        CSVRow(std::string&amp; unsplit_row, const char&amp; delim=&#39;,&#39;) {
            std::vector&lt;std::string&gt; parsed_row = SplitRow(unsplit_row, delim);
            date = parsed_row[0];
            merchant = parsed_row[1];
            charge_type = parsed_row[2];
            amount = parsed_row[3];
            payee = &quot;NONE&quot;;
        }

        // 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&lt;std::string&gt; SplitRow(std::string&amp; unsplit_row, const char&amp; delim) {
            std::istringstream stream(unsplit_row);
            std::string token;

            std::vector&lt;std::string&gt; 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 &lt;&lt; date &lt;&lt; &quot;\n&quot;;
    std::cout &lt;&lt; merchant &lt;&lt; &quot;\n&quot;;
    std::cout &lt;&lt; amount &lt;&lt; &quot;\n&quot;;
    std::cout &lt;&lt; payee &lt;&lt; &quot;\n&quot;;
    std::cout &lt;&lt; &quot;***********&quot; &lt;&lt; &quot;\n&quot;;
}

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 &lt;&lt; date &lt;&lt; &quot; , &quot; &lt;&lt; merchant &lt;&lt; &quot;, &quot; &lt;&lt; amount &lt;&lt; &quot;, &quot; &lt;&lt; payee &lt;&lt; &quot;\n&quot;;
    std::cout &lt;&lt; &quot;***********&quot; &lt;&lt; &quot;\n&quot;;
}

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&lt;std::string, std::string&gt; payee_map { buildPayeeMap() };
    
    std::vector&lt;CSVRow&gt; rows;
    std::fstream file(file_loc);
    std::string line;

    while(getline(file, line)) {
        if (line[0] == &#39;4&#39;) { // 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&lt;std::string&gt; SplitRow(std::string&amp; unsplit_row, const char&amp; delim) {
    // remove any carriage returns from the row
    unsplit_row.erase(std::remove(unsplit_row.begin(), unsplit_row.end(), &#39;\r&#39;), unsplit_row.end());
    std::istringstream stream(unsplit_row);
    std::string token;

    std::vector&lt;std::string&gt; row;

    while(getline(stream, token, delim)) {
        row.push_back(token);
    }

    return row;
}

huangapple
  • 本文由 发表于 2023年5月14日 04:48:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76244818.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定