4

string::substrの奇妙な動作に出くわしました。通常、私は Eclipse+MinGW でWindows 7でコーディングしますが、 Linux (Ubuntu 12.04) で Eclipse を使用してラップトップで作業しているときに、結果の違いに気付きました。

テキスト行で満たされたvector< string >で作業していました。手順の 1 つは、行から最後の文字を削除することでした。

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 ));

もちろん、Linux の方法は Windows では間違った方法で動作します (最後の 2 文字をトリミングするか、最後の前の文字を置き換える)。

問題は、myString.size() が Windows では文字数を返すのに対し、Linux では文字数 + 1 を返すようです。Linux では改行文字がカウントされるのでしょうか?

C++ およびプログラミング全般の初心者として、なぜそうなるのか、プラットフォームに依存しないようにするにはどうすればよいのか疑問に思います。

私が疑問に思っているもう1つのことは、 substrまたはreplaceのどちらの方法が望ましい(より速い)かということです。

編集:文字列を埋めるために使用される方法は、私が書いたこの関数です:

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
}
4

3 に答える 3

9

テキスト ファイルは、異なるオペレーティング システムで同一ではありません。Windows は 2 バイト コードを使用して行の終わりをマークします: 0x0D、0x0A。Linux は 1 バイト、0x0A を使用します。getline(および他のほとんどの入力関数)は、コンパイルされたOSの規則を知っています。OS が行末を表すために使用する文字を読み取ると、その文字が「\n」に置き換えられます。したがって、Windows でテキスト ファイルを作成すると、行は 0x0D、0x0A で終わります。Linux でそのテキスト ファイルを読み取ると、getline0x0D が表示されて通常の文字として処理され、0x0A が表示されて行末として処理されます。

したがって、あるシステムから別のシステムにテキスト ファイルを移動するときは、テキスト ファイルをネイティブ表現に変換する必要があるというのが教訓です。ftpこれを行う方法を知っています。仮想ボックスで実行している場合は、システムを切り替えるときに手動で変換を行う必要があります。trUnix のコマンド ラインから実行するのは簡単です。

于 2012-10-06T14:37:26.413 に答える
4

これは、Windows では改行が CR+LF の 2 文字で表されるのに対し、Linux では LF のみ、Mac (OSX より前) では CR のみであるためです。

Linux on Linux システムで生成されたファイル、または Windows on Windows システムで生成されたファイルのみを使用する限り、心配する必要はありません。しかし、Linux で生成されたファイルを Windows で使用する必要がある場合、またはその逆の場合は、改行を正しく処理する必要があります。

最初のステップとして、ファイルをバイナリ モードstd::ofstream infile( "filename", std::ios_base::binary);で開く必要があります。その後、次の 3 つのオプションがあります。

  1. すべてのプラットフォームで単一の改行規則を決定し、それを一貫して使用する必要があります。
  2. 現在のファイルで使用されている改行規則 (通常、最初の行で使用されている改行をチェックすることによって実装されます) を検出し、それを変数に保存して、改行を処理する必要がある文字列関数に渡すことができる必要があります。
  3. dos2unix と unix2dos を使用してファイルを正しい改行に変換するようにユーザーに指示するか、ファイル転送に FTP が含まれる場合は ASCII モードを使用します。

または、言われたように、Boost を使用します。

于 2012-10-06T14:37:47.440 に答える
0

行末は、Windows と Linux/Unix で同じではありません。Windows は 2 バイトを使用し、Linux は 1 バイトを使用します。.nix コマンド ラインで tr を使用する方法を Google で検索すると、それらを変換する方法がわかります。

幸運を!

于 2012-10-06T21:50:38.663 に答える