简体   繁体   English

如何逐行阅读 c 中的通用换行支持?

[英]How to read line by line with universal newline support in c?

int n = NMAXVAL;
char line[MAXLINE];
int rowCount = 0;
char* token = NULL;

while (rowCount < n && fgets(line, MAXLINE, stdin))
{
    token = strtok(line, " ");
    checkToken(token, n);
    // do something
    rowCount++;
}

My function reads from stdin line by line and performs some tasks.我的 function 逐行读取标准输入并执行一些任务。 It works fine for me on Visual Studio.它在 Visual Studio 上对我来说很好用。 However, it acts differently on xcode. It took a while for me to realize that this is caused by the difference between \n , \r , and \n\r .但是,它在 xcode 上的行为不同。我花了一段时间才意识到这是由\n\r\n\r之间的差异引起的。 How do I make my code support these newline chars?如何让我的代码支持这些换行符?

update: consider this input:更新:考虑这个输入:

1
10
3 4
5 6 7

On visual studio, the function reads line by line.在 visual studio 上,function 逐行读取。 However, on Xcode it reads the first line just fine then it reads \n instead 10\n.然而,在 Xcode 上,它读取第一行就很好,然后它读取 \n 而不是 10\n。

On visual studio, the function reads line by line.在 Visual Studio 上,function 逐行读取。 However, on xcode it reads the first line just fine then it reads \n instead 10\n.但是,在 xcode 上,它读取第一行就好了,然后读取 \n 而不是 10\n。

The problem is not fgets() .问题不在于fgets() This problem is the same exact file is treated as different text files on different platforms.这个问题是相同的文件在不同的平台上被视为不同的文本文件

A simply solution is to create each text file, separately, on each platform using that platform's end-of-line convention.一个简单的解决方案是使用该平台的行尾约定在每个平台上分别创建每个文本文件。

Alternatively and harder, to read the same exact file on different platforms, create your own line read function that ID's an end-of-line in the various ways.或者更难的是,要在不同平台上读取相同的确切文件,请创建自己的行读取 function ,ID 以各种方式作为行尾。 Depending on goals, code may need to (re-)open the file in binary.根据目标,代码可能需要(重新)打开二进制文件。

Alternatively and meets many cases, open the file in text mode (as stdin does), use fgets() and strip various line endings off.或者,遇到许多情况,以文本模式打开文件(就像stdin一样),使用fgets()并去除各种行尾。

if (fgets(line, sizeof line, stdin)) {
  line[strcspn(line, "\n\r")] = '\0'; // truncate after first of \n, \r or \0
}

Since the line will be tokenized by whitespace, the input could be read by scanf which will ignore leading whitespace.由于该行将由空格标记,因此scanf可以读取输入,这将忽略前导空格。 So scanf does the tokenizing as a feature.所以scanf将标记化作为一项功能。
Before scanning a token, try to scan a line ending, \r or \n.在扫描令牌之前,请尝试扫描行结尾,\r 或 \n。 If successful, scan for consecutive line endings.如果成功,扫描连续的行尾。 This seems to be the issue with fgets , it stops on the first line ending and treats a consecutive line ending as a blank line and the input lines seem to end with a pair of line endings.这似乎是fgets的问题,它在第一行结束时停止,并将连续行结尾视为空白行,并且输入行似乎以一对行结尾结束。
If the scan for line ending fails, scanf will replace the non-matching character into the input stream.如果行尾扫描失败, scanf会将不匹配的字符替换为输入 stream。

#include <stdio.h>
#include <stdlib.h>

int main ( void) {
    char token[100] = "";
    char endline[2] = "";
    int rowcount = 0;
    int result = 0;

    while ( 1) {
        scanf ( "%*[ \t]"); //scan and discard any and all space and tab
        if ( 1 == scanf ( "%1[\r\n]", endline)) {
            ++rowcount;
            // scanf ( "%1[\r\n]", endline); // consume one \r or \n
            while ( 1 == scanf ( "%1[\r\n]", endline)) {
                //consume consecutive \r or \n
            }
        }
        if ( 1 == ( result = scanf ( "%99s", token))) {
            // checkToken ( token);
            // do somethingthing
        }
        if ( EOF == result) {
            break;
        }
    }

    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM