在Windows和Linux上,字符串大小不同

4
我发现了关于string::substr的奇怪行为。通常我在Windows 7上用Eclipse+MinGW编码,但是当我在笔记本电脑上使用Linux(Ubuntu 12.04)中的Eclipse时,我注意到结果不同。
我正在处理被填充了文本行的vector< string >。其中一步是从行中删除最后一个字符。
在win7 Eclipse中,我这样做:
for( int i = 0; i < (int)vectorOfLines.size(); i++ )
{
    vectorOfTrimmedLines.push_back( ((string)vectorOfLines.at(i)).substr(0, ((string)vectorOfLines.at(i)).size()-1) );
}

并且它的作用就像预期的一样(从每行末尾删除最后一个字符)。

但是在Linux中,这段代码无法削减。相反,我需要这样做:

//  -2 instead -1 character
vectorOfTrimmedLines.push_back( ((string)vectorOfLines.at(i)).substr(0, ((string)vectorOfLines.at(i)).size()-2) );

或者使用另一种方法:
vectorOfTrimmedLines.push_back( ((string)vectorOfLines.at(i)).replace( (((string)vectorOfLines.at(i)).size()-2),1,"",0 ));

当在Windows上使用Linux方法时(修剪最后2个字符或替换倒数第二个字符),会出现错误。
问题似乎是myString.size()在Windows中返回的是字符数,但在Linux中返回的是字符数+1。可能是因为Linux计算了新行符?
作为C ++和编程的新手,我想知道为什么会这样,并且如何使其独立于平台。
另一个我想知道的是:哪种方法更可取(更快)substr还是replace?
编辑: 用于填充字符串s的方法是我编写的此函数:
vector< string > ReadFile( string pathToFile )
{
    //  opening file
    ifstream myFile;
    myFile.open( pathToFile.c_str() );

    //  vector of strings that is returned by this function, contains file line by line
    vector< string > vectorOfLines;

    //  check if the file is open and then read file line by line to string element of vector
    if( myFile.is_open() )
    {
        string line;    //  this will contain the data read from current the file

        while( getline( myFile, line ) )    //  until last line in file
        {
            vectorOfLines.push_back( line );    //  add current line to new string element in vector
        }

        myFile.close(); //  close the file
    }

    //  if file does not exist
    else
    {
        cerr << "Unable to open file." << endl; //  if the file is not open output
        //throw;
    }

    return vectorOfLines;   //  return vector of lines from file
}

1
为自己减少压力,使用 Boost - Perception
1
展示用于填充字符串的方法。 - Benjamin Lindley
3
为什么要进行类型转换?为什么使用at而不是[]运算符?为什么循环中不使用迭代器?最后,您确定Linux和Windows中的字符串实际上是相同的吗? - Some programmer dude
7
我猜这些字符串在Linux和Windows中是完全相同的,但它们来自一个在Windows下编写的文本文件,所以有两个字符代表换行符。 - Pete Becker
2
“换行符在 Linux 上会被计算吗?” - 只要它在字符串中,它就总是会被计算,因为它是一个普通字符。我猜问题更多的是你的字符串本身就有不同的值。 - Christian Rau
显示剩余13条评论
3个回答

9

文本文件在不同操作系统上并非完全相同。Windows使用两个字节的编码标记行尾:0x0D,0x0A。Linux使用一个字节,即0x0A。

getline(以及大多数其他输入函数)知道它编译所用的操作系统的惯例;当它读取代表行尾的字符时,会将这些字符替换为 '\n'。因此,如果您在 Windows 下编写文本文件,则行尾以 0x0D、0x0A 结束;如果您在 Linux 下读取该文本文件,则 getline 认为 0x0D 是普通字符,然后认为 0x0A 是行尾。

因此,结论是当您将文本文件从一个系统移动到另一个系统时,必须将其转换为本地表示形式。 ftp 知道如何执行此操作。如果您在虚拟机中运行,则必须在切换系统时手动进行转换。可以通过 Unix 命令行中的 tr 轻松完成。


一针见血!这一定是原因。感谢您的教训! - RegEx

4
这是因为在Windows中,换行由两个字符CR+LF表示,而在Linux中只有LF,在Mac(OSX之前)中只有CR。
只要您仅在Linux系统上使用生成的文件或在Windows系统上使用生成的文件,您就不必担心。但是,一旦您需要在Windows上使用在Linux上生成的文件或反之亦然,您就需要正确处理换行符。
作为第一步,您需要以二进制模式打开文件 std::ofstream infile( "filename", std::ios_base::binary);,然后有三个选项:
  1. 您需要决定一个统一的换行规则,并始终使用它,
  2. 您需要能够检测当前文件中使用的换行规则(通常通过检查第一行使用的换行符实现),将其保存在变量中,并将其传递给需要处理换行符的字符串函数,
  3. 告诉用户将文件转换为正确的换行符,例如使用dos2unix和unix2dos,或者如果文件传输涉及FTP,则使用ASCII模式
或者,正如已经提到的那样,使用Boost。

只比我接受其他回复晚几秒钟,但感谢您的正确输入! - RegEx

0

Windows和Linux / Unix中的行尾不相同 - Windows使用两个字节,而Linux使用一个字节。谷歌如何在.nix命令行上使用tr,您将看到如何将它们转换。

祝你好运!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接