繁体   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