簡體   English   中英

使用getline從輸入文件中使用重定向命令“ <”從標准輸入中讀取的字符串無法正確附加

[英]String read in from stdin by getline using redirection command “<” from input file does not append correctly

問題陳述

我想附加一個字符串“真棒!” ,使用getline函數從stdin讀取到另一個字符串“ Ice creams”

因此產生“冰淇淋很棒!”

如果輸入是手動鍵入的,則附加操作將正常進行。

但是,如果輸入是通過重定向命令“ <”從文件中獲取的,則追加操作的行為不會類似。

因此制作很棒! 冰淇淋

讓我通過代碼演示問題。

#include<iostream>

int main()
{
    // err : will be read from stdin using getline
    // err : is expected to fail in appending
    std::string err;

    // ok  : will be modified internally
    // ok  : is expected to succeed in appending
    std::string ok = "Pancakes";

    std::cout<<"Before executing  std::getline..."<<std::endl;
    std::cout<<"err \t:\t"<<err<<std::endl;
    std::cout<<"ok \t:\t"<<ok<<std::endl;
    std::cout<<"-------------------"<<std::endl;

    // we now use getline to read in string value for err
    // stdin can have any string , let's assume it is "Ice creams"
    std::cout<<"-------------------"<<std::endl;
    std::cout<<"Please enter string manually or < from file "<<std::endl;
    std::getline(std::cin,err);
    std::cout<<"-------------------"<<std::endl;


    std::cout<<"After executing std::getline..."<<std::endl;
    std::cout<<"err \t:\t"<<err<<std::endl;
    std::cout<<"ok \t:\t"<<ok<<std::endl;
    std::cout<<"-------------------"<<std::endl;

    //-------------------------------------------//
    //               THE PROBLEM                 //
    //-------------------------------------------//
    // we try to append to err
    err += " are awesome !";
    // we try to append to ok
    ok  += " are awesome !";

    std::cout<<"After executing append operation..."<<std::endl;
    std::cout<<"Where,the '+=' operator is used..."<<std::endl;
    std::cout<<"err \t:\t"<<err<<std::endl;
    std::cout<<"ok \t:\t"<<ok<<std::endl;
    std::cout<<"-------------------"<<std::endl;


    return 0;
}

終端輸出

借助WSL功能在Windows 10計算機上運行的g ++進行編譯。

C:\test>wsl g++ test.cpp -o a.out -std=c++11

C:\test>wsl ./a.out
Before executing  std::getline...
err     :
ok      :       Pancakes
-------------------
-------------------
Please enter string manually or < from file
Ice creams
-------------------
After executing std::getline...
err     :       Ice creams
ok      :       Pancakes
-------------------
After executing append operation...
Where,the '+=' operator is used...
err     :       Ice creams are awesome !
ok      :       Pancakes are awesome !
-------------------

C:\test>wsl ./a.out < in-test.in
Before executing  std::getline...
err     :
ok      :       Pancakes
-------------------
-------------------
Please enter string manually or < from file
-------------------
After executing std::getline...
err     :       Ice creams
ok      :       Pancakes
-------------------
After executing append operation...
Where,the '+=' operator is used...
 are awesome !  Ice creams
ok      :       Pancakes are awesome !
-------------------

C:\test>

結果

  • Append可以為標准輸入中的手動輸入產生正確的結果。
  • Append從stdin的in-test.in文件中產生亂碼結果。

注意: in-test.in文件包含帶有字符串“ Ice creams ”的一行。

注意:如果很難注意到該錯誤,請允許我指出。

這是行真棒! 冰淇淋位於終端輸出的尾部。

問題

  • 為什么會這樣?
  • 如何避免呢?

請注意,該行甚至不包含所謂的前導"err \\t:\\t"輸出,但是err的輸出顯示了它應該在哪里?

那只能是因為輸入文件包含一個前導的回車符'\\r'

知識點

一些程序員的好人提到字符串中可以包含'\\r'

問題來源

有意義的是,Linux,Macintosh和Windows具有不同的行終止符,因此當我們要將文件從一個系統傳輸到另一個系統並期望它們正常工作時,可能會遇到一些問題。

這個問題的解釋很漂亮: CR LF,LF和CR換行類型之間的區別?

就是這樣。 我使用Notepad.exe創建了文件,因此自動為它分配了CRLF行終止符。 但是,由於我使用Linux的Windows子系統(WSL) (本質上是在Windows 10中運行的Ubuntu 編譯程序,因此a.out創建的可執行文件是linux可執行文件。

將帶有CRLF行終止符的文件重定向到可執行文件stdin中導致了此問題。

使用MinGW或MSYS2后,遷移到WSL的用戶可能會遇到此特定問題。

既然如此,MinGW和MSYS2可以很好地與CRLF編碼配合使用,而WSL則不能。

固定

只需使用稱為unix2dosdos2unix的工具更改行終止符unix2dos

顧名思義,它們會將文本文件轉換為與基於dos和unix的OS兼容。

  • 使用Linux / WSL創建的文件以使其與Windows可執行文件兼容時,請使用unix2dos
  • 使用Windows創建的文件以使其與Linux / WSL可執行文件兼容時,請使用dos2unix

演示版

C:\test>wsl g++ test.cpp -o a.out -std=c++11

C:\test>wsl unix2dos in-test.in
unix2dos: converting file in-test.in to DOS format ...

C:\test>wsl file in-test.in
in-test.in: ASCII text, with CRLF line terminators

C:\test>wsl ./a.out < in-test.in
Before executing  std::getline...
err     :
ok      :       Pancakes
-------------------
-------------------
Please enter string manually or < from file
-------------------
After executing std::getline...
err     :       Ice creams
ok      :       Pancakes
-------------------
After executing append operation...
Where,the '=' operator overloading is used...
 are awesome !  Ice creams
ok      :       Pancakes are awesome !
-------------------

C:\test>wsl dos2unix in-test.in
dos2unix: converting file in-test.in to Unix format ...

C:\test>wsl file in-test.in
in-test.in: ASCII text

C:\test>wsl ./a.out < in-test.in
Before executing  std::getline...
err     :
ok      :       Pancakes
-------------------
-------------------
Please enter string manually or < from file
-------------------
After executing std::getline...
err     :       Ice creams
ok      :       Pancakes
-------------------
After executing append operation...
Where,the '=' operator overloading is used...
err     :       Ice creams are awesome !
ok      :       Pancakes are awesome !
-------------------

結果

  • WSL創建的可執行文件最初不適用於帶有CRLF行終止符的輸入文件,然后

  • 使用工具dos2unix將文件的行終止符更改為與Linux兼容,從而與WSL兼容,從而使程序成功運行。 因此,修復程序起作用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM