【问题标题】:what are the possible new line characters in different OS不同操作系统中可能的换行符是什么
【发布时间】:2018-05-09 09:54:16
【问题描述】:

我们有一个代码逐行读取文件,每一行都存储为一个字符串。问题是 Linux 在行尾添加了 '\n'; windows 添加 '\r\n' 和 ios 在行尾添加 '\r'。我们想用 '\0' 替换所有这些特殊字符,以便得到我们的字符串。

是否有任何其他操作系统添加了其他字符?我们需要处理它。

针对下面的cmets,我尝试使用文本文件模式

file = fopen ( filename, "rt" );
while(fgets ( buf, sizeof buf, buf ) != NULL)
{
    (*properties)->url= (char *) malloc(strlen(buf)+1);
    strcpy( (*properties)->url, buf);
/////...................more code

}

//line x-->
strncpy(url,properties->url,strlen(properties->url));

在第 x 行,gdb 打印 "https://example.com/file\r\n\0" 用于属性->url

我的网址是“https://example.com/file

【问题讨论】:

  • 也许是this will help you。检查获得赏金的答案。
  • 不幸的是,几乎没有办法覆盖所有未知的异国操作系统(由一些默默无闻的狂热狂人设计的操作系统)。您可能应该首先将您的范围限制在完善的操作系统上。
  • 还有其他操作系统添加的其他字符吗?我们需要处理它。 为什么? C 标准有一个明确定义的“文本”模式用于将所有换行符转换为\n 字符的流,
  • 您的问题是您正在将其作为二进制文件读取。如果您以文本文件的形式读取或写入它,那么您并不关心操作系统如何解释“\n”。
  • 祝你好运,用 RECFM=VB dataset on IBM's MVS/OS 上的 NUL 替换操作系统提供的记录(行)边界。

标签: c


【解决方案1】:

有三种相对常见的换行约定:\r\n\n\r,当编辑者对换行约定感到困惑时,可能会出现第四种换行约定 \n\r。如果一种方法支持通用换行符,它同时支持所有四个,即使是固定的。

使用通用换行支持逐行读取文件很容易。唯一的问题是来自行缓冲源的交互式输入看起来像是晚了一行。为了避免这种情况,可以将行读入动态缓冲区,但不包括换行符;并在阅读下一行时使用换行符。例如:

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

ssize_t  getline_universal(char **dataptr, size_t *sizeptr, FILE *in)
{
    char   *data = NULL;
    size_t  size = 0;
    size_t  used = 0;
    int     c;

    if (!dataptr || !sizeptr || !in) {
        errno = EINVAL;
        return -1;
    }

    if (*sizeptr) {
        data = *dataptr;
        size = *sizeptr;
    } else {
        *dataptr = data;
        *sizeptr = size;
    }

    /* Ensure there are at least 2 chars available. */
    if (size < 2) {
        size = 2;
        data = malloc(size);
        if (!data) {
            errno = ENOMEM;
            return -1;
        }
        *dataptr = data;
        *sizeptr = size;
    }

    /* Consume leading newline. */
    c = fgetc(in);
    if (c == '\n') {
        c = fgetc(in);
        if (c == '\r')
            c = fgetc(in);
    } else
    if (c == '\r') {
        c = fgetc(in);
        if (c == '\n')
            c = fgetc(in);
    }

    /* No more data? */
    if (c == EOF) {
        data[used] = '\0';
        errno = 0;
        return -1;
    }

    while (c != '\n' && c != '\r' && c != EOF) {

        if (used + 1 >= size) {
            if (used < 7)
                size = 8;
            else
            if (used < 1048576)
                size = (3 * used) / 2;
            else
                size = (used | 1048575) + 1048577;

            data = realloc(data, size);
            if (!data) {
                errno = ENOMEM;
                return -1;
            }

            *dataptr = data;
            *sizeptr = size;
        }

        data[used++] = c;
        c = fgetc(in);
    }

    /* Terminate line. We know used < size. */
    data[used] = '\0';

    /* Do not consume the newline separator. */
    if (c != EOF)
        ungetc(c, in);

    /* Done. */
    errno = 0;
    return used;
}

上述函数的工作方式与 POSIX.1-2008 getline() 非常相似,不同之处在于它支持所有四种换行约定(甚至是混合的),并且它在读取的行中省略了换行符。 (也就是说,换行符不包含在返回值或动态分配的缓冲区中。换行符留在流中,供下一个getline_universal() 操作使用。)

与标准函数不同,getline_universal() 总是将 errno: 设置为零,如果成功,否则非零。如果您不喜欢这种行为,请随时更改。

作为一个用例示例:

int main(void)
{
    unsigned long  linenum = 0u;
    char          *line_buf = NULL;
    size_t         line_max = 0;
    ssize_t        line_len;

    while (1) {
        line_len = getline_universal(&line_buf, &line_max, stdin);
        if (line_len < 0)
            break;

        linenum++;

        printf("%lu: \"%s\" (%zd chars)\n", linenum, line_buf, line_len);
        fflush(stdout);
    }

    if (errno) {
        fprintf(stderr, "Error reading from standard input: %s.\n", strerror(errno));
        return EXIT_FAILURE;
    }

    /* Not necessary before exiting, but here's how to
       safely discard the line buffer: */
    free(line_buf);
    line_buf = NULL;
    line_max = 0;
    line_len = 0;

    return EXIT_SUCCESS;
}

请注意,由于free(NULL) 是安全的,您可以在调用getline_universal(&amp;line_buf, &amp;line_max, stream) 之前丢弃缓冲区(使用free(line_buf); line_buf = NULL; line_max = 0;)。

【讨论】:

  • 你有什么理由不能简单地做bool new_line = false; if(isspace(ch)) { while(ch == '\n' || ch == '\r') { new_line = true; ch = fgetc(in); } }
  • @Lundin:这也会跳过(消耗)空行。
  • 如果您检查提供的布尔变量,则不会。
  • @Lundin:while (ch=='\n' || ch=='\r') { new_line=true; ch=fgetc(in); } 循环肯定会消耗空行。这就是为什么我没有使用它。如所写,我的答案中的代码即使使用行缓冲交互式输入也能正常工作,并且不会跳过空行。唯一的缺点是它使用换行符而不告诉调用者确切的换行符类型。
  • "函数的工作方式很像 ... getline()" 有额外的区别:它可以设置errno = 0 - 最出乎意料的。它将行尾字符留在流中。如果最后一行是空行,则返回 -1。
猜你喜欢
  • 2011-01-02
  • 2011-04-12
  • 2013-11-07
  • 2011-10-26
  • 1970-01-01
  • 2012-09-29
  • 2012-06-26
  • 1970-01-01
  • 2010-11-18
相关资源
最近更新 更多