行计数,如何处理CRLF?

时间:2012-06-11 15:22:08

标签: c++ windows carriage-return linefeed

我正在编写一个简单的包装类,用于逐个字符地扫描字符流。

Scanner scanner("Hi\r\nYou!");
const char* current =  scanner.cchar();
while (*current != 0) {
    printf("Char: %d, Column: %d, Line: %d\n", *current, scanner.column(), scanner.line());
    current = scanner.read();
}

C:\Users\niklas\Desktop>g++ main.cpp -o main.exe
C:\Users\niklas\Desktop>main.exe
Char: 72, Column: 0, Line: 0
Char: 105, Column: 1, Line: 0
Char: 13, Column: 0, Line: 1
Char: 10, Column: 0, Line: 2
Char: 89, Column: 1, Line: 2
Char: 111, Column: 2, Line: 2
Char: 117, Column: 3, Line: 2
Char: 33, Column: 4, Line: 2

这个例子已经显示了我遇到的问题。可以将\r解释为换行符,以及\n。但是在一起(\r\ n)它们也只是一个单个新行!

处理行号和列号的函数是:

void _processChar(int revue) {
    char chr = _source[_position];
    if (chr == '\r' or chr == '\n') {
        _line += revue;
        _column = 0;
    }
    else {
        _column += revue;
    }
}

当然,我可以看一下当前位置后出现的字符但是:我检查源上的NULL终止,因为我希望能够处理可能包含\0个字符的字符流,而不会在此时终止。

如何以这种方式处理CRLF?

编辑1 :DOH!这似乎工作正常。这在任何情况下都是安全的,还是我在某个地方有问题?

void _processChar(int revue) {
    char chr = _source[_position];

    bool is_newline = (chr == '\r' or chr == '\n');
    if (chr == '\n' and _position > 0) {
        is_newline = (_source[_position - 1] != '\r');
    }

    if (is_newline) {
        _line += revue;
        _column = 0;
    }
    else {
        _column += revue;
    }
}

谢谢!

4 个答案:

答案 0 :(得分:3)

大多数现代系统处理\n作为当前目标平台的换行符,因此如果您只检查\n,所有这些都会自动发生。

答案 1 :(得分:1)

您可能需要在流包装器中保持状态 - 一个无状态包装器,正如您已经注意到的那样,只是不能执行此操作,因为每个输出都可以(根据定义)依赖于先前的输出

答案 2 :(得分:0)

您的_processChar似乎没有增加流读取位置。更改后,您可以实施完整的换行检查:

void _processChar(int revue) {
    char chr = _source[_position];
    if (chr != '\r' and chr != '\n') {
        _column += revue;
        return;
    }
    if (if chr == '\r' and _source[_position + 1] == '\n')
        ++_position;
    _line += revue;
    _column = 0;
}

答案 3 :(得分:0)

这对我来说似乎是合法的:

void _processChar() {
    char chr = _source[_position];

    // Treat CRLF as a single new-line
    bool is_newline = (chr == '\r' or chr == '\n');
    if (chr == '\n' and _position > 0) {
        is_newline = (_source[_position - 1] != '\r');
    }

    if (is_newline) {
        _line += 1;
        _column = 0;
    }
    else {
        _column += 1;
    }
}

在处理\n时,它会检查上一个字符是否为回车符(\r)。如果是这样,则行号增加。

此外,在检查前一个字符之前,它会测试是否实际上是前一个字符(and _position > 0)。

我已经删除了 int revue 参数,因为我刚注意到我想要实现的目标是不可能的,因为我试图实现它。我希望能够在源代码中向后退,但我无法从上一行检索列号。