MSVC 和 g++ 中的不同行尾

Posted

技术标签:

【中文标题】MSVC 和 g++ 中的不同行尾【英文标题】:Different line endings in MSVC and g++ 【发布时间】:2020-12-04 10:35:11 【问题描述】:

我正在尝试解析文件中的文本,我必须在其中检测空行。 我在 2 个地方运行代码:

win 10,视觉工作室 2019(MSVC) 在 WSL、ubuntu 20.04、g++ 下

相同的计算机,相同的文件,相同的代码。

while (getline(inputFile, line))

    if (line.length() == 1)
    
        std::cout << "Empty line" << std::endl;
    
/*blabla*/

使用此代码,MSVC 不会打印空行,而 g++ 会。


if (line.empty())

    std::cout << "Empty line" << std::endl;

使用此代码,MSVC 会找到空行,而 g++ 不会。


if (int(line[0]) == 10 || int(line[0]) == 13)

    std::cout << "Empty line" << std::endl;

使用此代码 g++ 会找到空行,MSVC 不会

    改变行尾的是Linux内核还是编译器? 在每个系统上始终检测行尾和空行的正确方法是什么?

【问题讨论】:

\r, \n 可以替换幻数 10,13。 行尾的约定取决于操作系统。有 Windows 约定 (\r\n) 和 Unix 约定 (\n),老前辈记得经典的(在 OS X 之前)Mac 约定 (\r)。如果您在不同的操作系统之间传输文本文件,您需要使用某种工具重新编码它们,或者准备好解析程序中的不同行尾。自然地,Unix 程序会将\r 视为常规字符而不是行尾序列的一部分。丢弃它是你的责任。 注意:在空行上执行line[0] 会使程序具有未定义的行为。 您可能需要检查常见的unix2dosdos2unix 工具,它们在\n 之前添加或删除\r 【参考方案1】:

您的困难源于您在同一台机器上混合了 Windows 和 Linux 行尾。 WSL 是一个类似 Linux 的环境,在 WSL 上处理 Windows 文件与在真正的 Linux 机器上处理它们没有什么不同,即有问题。

std::getline 去除\n (0x0A) 行尾,另外在MSVC 中,以文本模式读取文件会自动去除\r (0x0D) 字符。后者不会在 Linux 上发生。

因此,在非 Windows 平台上读取 Windows 文本文件(以 \r\n 行结尾)将删除 \n,但将 \r 留在行尾。

如果您想处理这种情况,您可以手动去除尾随的\r。例如

while (std::getline(inputFile, line))

    if (!line.empty() && line.back() == '\r')
    
        line.pop_back();
    
    if (line.empty())
    
        std::cout << "Empty line" << std::endl;
    

在调试时以二进制模式打印出line 通常很有帮助,因为\r\n 是不可见字符。

【讨论】:

以上是关于MSVC 和 g++ 中的不同行尾的主要内容,如果未能解决你的问题,请参考以下文章

MSVC++14 上的 C++11 中的不可能的快速委托

UITableView - 具有相同数组的部分中的不同行

具有数组字段的 bigquery 表中的不同行

从一个 MySqli 查询中的不同行获取值

ListView 中的不同行布局

在一个表中的不同行和不同列中查找相同的值SQL