std :: getline()读取马车返回 r,如何避免

std::getline() reads carriage return into the string, how to avoid that?

本文关键字:何避免 返回 读取 getline std 马车      更新时间:2023-10-16

我需要从一个 Stern(engl。:star)对象的t t t t t thex文件中读取所有属性。我需要用""替换字符串"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;
}

stern.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 */

问题在于,在Windows中,Newline在CR + LF中表示为:"rn",在UNIX中,它是LF,它只是"n"

您的std::getline(...)命令正在读取直到"leerrn"中的"n"并丢弃"n",您所产生的字符串将是:

"leerr"

要解决此问题并在UNIX/Windows之间转换文件,有2个工具dos2unixunix2dos。Ubuntu等效物为fromdostodos,您将需要fromdos将Windows文本文件转换为Unix文本文件。

要测试文件使用CR + LFLF您可以做:

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

在Unix&amp;Linux Stackexchange网站。


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

应该是:

if (obj.m_Sternbild == "leerr")

没有逃脱后斜线,因为r已读取到字符串中。

编辑:

AS @freelanceconsultant 在下面的评论中写:上述答案不是一般解决方案。因为在Windows或Unix上编译的二进制文件应适用于两个平台的文本文件。

有两种解决方案。

显而易见的是,与输入的两个不同版本进行比较。使用std::getline Windows结果是"leerr",UNIX结果是"leer"

if (obj.m_Sternbild == "leerr" || obj.m_Sternbild == "leer")

另一个解决方案是将newline表示形式归一化为一种形式,而仅对此形式进行检查。这是一个口味和性能的问题,因为您需要创建新的字符串。以他的答案为例。

您可以使用它来删除std::getline返回的任何不需要字符。

// std::string s;
// std::getline(input, s);
s.erase(std::remove(s.begin(), s.end(), 'r' ), s.end());
s.erase(std::remove(s.begin(), s.end(), 'n' ), s.end());

这在Linux系统上起作用,其中输入文件格式使用了Line Endings CRLF。这是因为在Linux系统上,std::getline正在搜索n字符,因此它在每行末端返回一个额外的r

我不会期望这能像您在其他系统上的预期一样工作。例如,它可能是:

  • 在OS X上,getline 可能搜索r,含义后续调用返回一个带有n string 。(以上将可能仍然有效,因为您仍然删除n
  • 在Windows上,getline搜索rn。如果在OS X或Linux上产生文件,我将假设 getline无法将输入分为不同的行,而只返回整个输入。
  • 我不确定上述两个点,并且都没有测试任何一种情况,因为我碰巧没有可用的OS X系统或用于开发工作的Windows系统设置。

,似乎它保存在对象中,而不是仅保存在对象中 " leer"

您可以修剪从getline获得的字符串,也可以与stringstream结合使用getline

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

现在trimmed_string将仅包含所需的字符串,无端线,训练或领先的空格或其他东西。

ps:这仅在要读取的字符串不包含空格本身时才有效。如果这样,您必须诉诸于从 getline获得的字符串进行按摩或选择一些特殊角色,或者在阅读后选择一些特殊字符(例如,阅读" alpha_centauri",然后用" _"替换为"获取" alpha centauri")。