【问题标题】:std::getline() reads carriage return \r into the string, how to avoid that?std::getline() 将回车符 \r 读入字符串,如何避免这种情况?
【发布时间】:2017-08-30 09:06:55
【问题描述】:

我需要为一个Stern (engl.: Star) 对象从一个如下所示的文本文件中读取所有属性。我需要用"" 替换字符串"leer",但也可以有一个不应替换为"" 的有效字符串。

即,对于另一个 Stern 对象,也可能是 "leer" 而不是 "Sol"

问题:
问题是它不会用"" 替换"leer"。似乎它在对象中保存了"leer\\r",而不仅仅是"leer",但我也尝试替换"leer\\r",但它仍然不起作用。

这是文本文件中应阅读的Stern

0
Sol
0.000005
0.000000
0.000000
leer
1
0

这是我的operator >> 来阅读它:

istream& operator>>(istream& is, Stern& obj)
{
    string dummy;
    is >> obj.m_ID;
    getline(is, dummy);
    getline(is, obj.m_Bez);

    if (obj.m_Bez == "leer")
        obj.m_Bez = "";

    is >> obj.m_xKoord >> obj.m_yKoord >> obj.m_zKoord;
    getline(is,dummy);
    getline(is,obj.m_Sternbild);

    if (obj.m_Sternbild == "leer")
        obj.m_Sternbild = "";

    is >> obj.m_Index >> obj.m_PrimID;

    return is;
}

船尾.h:

#ifndef STERN_H
#define STERN_H
#include <string>
#include <iostream>

using namespace std;

class Stern
{
public:
    Stern();
    // 2.a)
    //Stern(int m_ID, string m_Bez, float m_xKoord, float m_yKoord, float m_zKoord, string m_Sternbild, int m_Index, int m_PrimID); 
    virtual ~Stern();

    void print() const; // 1.b)
    friend ostream& operator<<(ostream& os, const Stern& obj); // 1.b)i.
    friend istream& operator>>(istream& is, Stern& obj);


private:
    int m_ID;
    string m_Bez;
    float m_xKoord;
    float m_yKoord;
    float m_zKoord;
    string m_Sternbild;
    int m_Index;
    int m_PrimID;
};

#endif /* STERN_H */

【问题讨论】:

  • 你显示的代码有什么问题?
  • 问题是它没有用“”替换“leer”而且它似乎在对象中保存了“leer\\r”而不是只保存了“leer”,但我试图替换"leer\\r" 也一样,还是不行。
  • 如果输入与您的描述中的输入相同,那么我猜这是因为“leer”字之前的空格?不要忘记您正在使用 getline(is, obj.m_Bez); 并且不会删除空格。尝试先修剪字符串,然后检查是否相等。
  • 保存的确切值是: m_ID: 0 m_Bez: "Sol\\r" m_xKoord:4.99999987e-06
  • 如果您在调试器中逐行执行代码,您会注意到什么?您读取的值是否正确,是否符合您的预期?

标签: c++ operator-overloading


【解决方案1】:

问题在于,在 Windows 中,newline 表示为 CR + LF,即:"\r\n",而在 Unix 中,LF 表示为 "\n"
您的std::getline(...) command 正在读取到"\n" 中的"leer\r\n",您的结果字符串将是:

"leer\r"

为了解决这个问题并在 Unix/Windows 之间转换文件,有两个工具 dos2unixunix2dos。 Ubuntu 等价物是 fromdostodos,您需要 fromdos 将 Windows 文本文件转换为 Unix 文本文件。

要测试文件是否使用CR + LFLF,您可以这样做:

dos2unix < myfile.txt | cmp -s - myfile.txt

这是在Unix & Linux StackExchange site 上发布的。


它似乎将"leer\\r" 保存在对象中,而不仅仅是"leer",但我也尝试替换"leer\\r",但它仍然不起作用。我仍然不明白为什么我的if (obj.m_Sternbild == "leer\\r") 不起作用,因为 imo 它应该起作用?

应该是:

if (obj.m_Sternbild == "leer\r")

不转义反斜杠\,因为\r 被读入字符串。

【讨论】:

    【解决方案2】:

    它似乎在对象中保存了“leer\r”,而不仅仅是 “偷看”

    您可以修剪从getline 获得的字符串,也可以将getlinestringstream 结合使用:

     std::string line;
     getline(is,line);
     std::stringstream ss(line);
     std::string trimmed_string;
     ss >> trimmed_string;
    

    现在trimmed_string 将只包含所需的字符串,没有结束行、训练或前导空格或其他内容。

    PS:这仅在您要读取的字符串本身不包含空格时才有效。如果是这种情况,您必须对从getline 获得的字符串进行更复杂的按摩,或者选择一些特殊字符,您可以在阅读后用空格替换(例如,阅读“Alpha_Centauri”,然后将“_”替换为“ " 得到“半人马座阿尔法星”)。

    【讨论】:

    • 是的,问题是有 m_Bez(基本上是星星的名字)看起来像这样:“96 G. Psc”而且我不允许以任何方式更改 txt 文件。
    • @CraigHarrison 然后不幸的是我的回答没有帮助。也许我稍后会编辑它....
    • 感谢您帮助我。我真的很感激!
    • 请注意std::getline() 将按原样读取整行直到换行符,而ss &gt;&gt; 将跳过前导空格,然后读取到第一个空格或字符串结尾,以先发生者为准。因此,ss &gt;&gt; 不只是在换行之前在行中有任何非前导/尾随空格时进行修剪。你会砍掉实际数据。修剪涉及仅扫描和删除前导 + 尾随空格,而不是中间的任何空格。
    • @RemyLebeau 这就是我的 PS 的意义所在。我希望一个简单的解决方案可以提供帮助,但还没有时间改进答案
    猜你喜欢
    • 1970-01-01
    • 2019-07-08
    • 2013-09-14
    • 2020-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-18
    相关资源
    最近更新 更多