【问题标题】:remove characters from EOL从 EOL 中删除字符
【发布时间】:2013-06-07 10:30:39
【问题描述】:

我从串行设备读取缓冲区。它会返回这些结果(每次 2 行)

Hello World.
My name is John.

Hello World.^M^JMy name 
is Mike.

Hello World.^M^JMy name 
is ^M^JERROR Peter.

这些结果在 Linux 命令行中。 ^M^J 是 EOL,在 Windows 中表示 \r\n。第一个结果还可以,但其他两个很糟糕。有没有办法检查 ^M^J 字符并删除它们?因为我想要这些结果:

Hello World.
My name is John.

Hello World.
My name is Mike.

Hello World.
My name is Peter.

通过这段代码我读取了缓冲区

char buff[150];
memset(buff, 0, sizeof(buff));
for (;;)
{
  n=read(fd,buff,sizeof(buff));
  printf("%s", buff);
}

更新

我以这种方式打开和配置我的设备

int open_port(void)
{
int fd; // file description for the serial port 
fd = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY);
if(fd == -1) // if open is unsucessful
{
 //perror("open_port: Unable to open /dev/ttyAMA0 - ");
 printf("open_port: Unable to open /dev/ttyAMA0. \n");
}
else
{
  fcntl(fd, F_SETFL, 0);
  printf("port is open.\n");
}

return(fd);
} //open_port

并配置端口

int configure_port(int fd)      // configure the port
{
 struct termios port_settings;      // structure to store the port settings in
 cfsetispeed(&port_settings, B9600);    // set baud rates
 cfsetospeed(&port_settings, B9600);
 port_settings.c_cflag &= ~PARENB;    // set no parity, stop bits, data bits
 port_settings.c_cflag &= ~CSTOPB;
 port_settings.c_cflag &= ~CSIZE;
 port_settings.c_cflag |= CS8;
 tcsetattr(fd, TCSANOW, &port_settings);    // apply the settings to the port
 return(fd);

} //configure_port

【问题讨论】:

  • 我认为您必须逐个字符地检查 ascii 值 en.wikipedia.org/wiki/ASCII#ASCII_control_code_chart
  • read() 一个 EOF 之后在 Windows 中会发生什么?阅读停止了吗?
  • 我不知道在 Windows 中会发生什么。我使用 Linux,我有这些字符
  • @mf_ 显然 EOF 是 EOL 的拼写错误。

标签: c linux newline


【解决方案1】:

printf() 看到\r\n 而不是单独的\n 时,它的行为方式很有趣。它将成对的字符行尾解释为不是行尾,因此它没有执行通常的行尾功能,而是向您显示^M^J。简单地消除\r 将为您提供所需的行为。

  char buff[150];
  int n = read(fd,buff,sizeof(buff));  // buff is not NUL terminated
  if (n < 0) {
    // deal with I/O error
    }
  if (n == 0) {
    // deal with end-of-file
    }
  else {
    for (int i=0; i<n; i++) {
      if (isprint(buff[i]) || (buff[i] == '\n')) {
        putchar(buff[i]);
      }
      else if (buff[i] == '\r') {
        ; // drop it
      }
      else {
        ; // TBD deal with unexpected control codes and codes 127-255
      }
    }
  }

注意事项:
1) 您之前使用read() 从串行设备填写了buff。由于串行设备是二进制的,读取的字节可能包括 NUL 字节。读取在缓冲区中散布 NUL 字节的字节数组并将其视为 NUL 终止的字符串将导致丢失数据。
2) read() 不会将 \0 字节附加到它读取的缓冲区的末尾,并且可能会解释您的“错误”。
3) 通常,您正在读取二进制设备并写入文本输出。传入的二进制流可能是使用\r\n 作为行尾的ASCII 文本,但您的stdout 想使用\n 作为行尾。只要字节是可打印的 ASCII 码(代码 32-126),打印到stdout 时,一切都会按预期工作。但是当你读取\0\r\n、配对\r\n、其他控制字符、通信错误等时,你需要考虑你希望它如何显示。

【讨论】:

  • 感谢您的回答。我用我写的打开和配置函数更新了这篇文章
  • 一个问题,因为我得到 fd 作为 int,我可以将它与 fgets 一起使用吗?我认为不能!
  • 我在您的更新中看到了这一点,并将修改我的答案。 (应该在原版read()看到过。)
【解决方案2】:

首先,^M^J 是行尾,而不是文件尾。

其次,read 从指定的文件描述符中读取二进制数据。它会读取您指定的字符数,直到到达文件末尾,或者出现错误。如果您想一次读取行,一次读取一个字节,或者使用其他一些面向行的 I/O 调用(sscanf 之类的)

【讨论】:

  • 我们的,敲我的头,答案已删除,对不起。
【解决方案3】:

您可以查看this 问题,该问题提出了一个从文件中读取行并处理 Windows 回车的函数。

【讨论】:

    【解决方案4】:

    O_TEXT打开文件

    #include <fcntl.h>
    fd = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY | O_TEXT);
    

    【讨论】:

    • 使用此解决方案(使用此标头)我有错误:'O_TEXT' 未在此范围内声明。
    • 任一 1) O_TEXT 位于包含文件中,例如 &lt;rsync.h&gt;&lt;io.h&gt;&lt;fcntl.h&gt;,或 2) &lt;sys/stat.h&gt; 或您正在使用类似 Unix 的系统不区分二进制文件和文本文件。如果 #2 是这种情况并且发起消息的单元类似于 PC,那么 应该使用 O_TEXT 标志。
    猜你喜欢
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2013-07-06
    • 2016-07-26
    • 2013-09-18
    • 2011-11-22
    相关资源
    最近更新 更多