使用 sscanf 删除 [] 中的尾随空格

问题描述 投票:0回答:1

我需要解析

utmpdump /var/log/wtmp
返回的行。它们的格式如下:

[8] [13420] [    ] [        ] [pts/3       ] [                    ] [0.0.0.0        ] [2024-07-22T11:18:29,836564+00:00]
[7] [13611] [ts/3] [john    ] [pts/3       ] [192.168.1.38        ] [192.168.1.38   ] [2024-07-22T11:21:30,065856+00:00]
[8] [13611] [    ] [        ] [pts/3       ] [                    ] [0.0.0.0        ] [2024-07-22T11:21:41,814051+00:00]

特点是:

  • 所有列都包含在
    []
    ,
  • 每行有固定的列数,
  • 每列可以包含文本或为空(仅空格)。实际上并不是全部,但最好假设全部,
  • 当该列包含文本时,其长度可能会有所不同(可以添加前缀的上限,即 64 个字符,包括
    \0
    ),
  • 当列中有文本时,它永远不会有前面的空格,但通常会有尾随空格。

如何将这样的一行解析为 8 个

char*
变量,其中
sscanf
具体是什么?我无法解决的问题是如何修剪尾随空格,同时允许
[]
之间的字符串长度变化。还可以用
sscanf
吗?

我有一个没有

sscanf
的可行解决方案,但是这个解决方案必须专门使用
sscanf
来完成。在
sscanf
解析之后修剪空格是一种备份解决方案,但我尝试通过
sscanf
完全解析来完成此操作。

c string whitespace
1个回答
0
投票

使用

"%n"
确定扫描部分的偏移。

*scanf()
不喜欢形成 0 长度的字符串,因此在扫描列时,请将
[
视为字段的一部分,以确保字段中至少有 1 个字符。 后来,启动字段1通过了
'['

#include <stdio.h>

char *cut_up_line(char *offset[8], char * line) {
  for (int i = 0; i < 8; i++) {
    //int field_start;
    int field_end;
    int column_end = 0;
    // If possible for the line to include unusually white-spaces,
    // adjust format to include them: "%*[^] \t\r\v\f]%n ] %n"
    sscanf(line, "%*[^] \t]%n ] %n", &field_end, &column_end);
    if (column_end == 0) {
      // debug: printf("-%d <%s>\n", i, line);
      return NULL;
    }
    // Maybe add test here that *line is a '['.
    offset[i] = line + 1;
    line[field_end] = '\0';
    line += column_end;
    // debug: printf("+%d <%s>\n", i, offset[i]);
  }
  return line;
}


void test(char *line) {
  printf("<%s>\n", line);
  char *field[8];
  if (cut_up_line(field, line) == NULL) {
    printf("** Failed **\n");
  } else {
    for (int i = 0; i < 8; i++) {
      printf("  %d:<%s>\n", i, field[i]);
    }
  }
}


int main() {
  char s1[] = "[8] [13420] [    ] [        ] [pts/3       ] [                    ] [0.0.0.0        ] [2024-07-22T11:18:29,836564+00:00]";
  char s2[] = "[7] [13611] [ts/3] [john    ] [pts/3       ] [192.168.1.38        ] [192.168.1.38   ] [2024-07-22T11:21:30,065856+00:00]";
  char s3[] = "[8] [13611] [    ] [        ] [pts/3       ] [                    ] [0.0.0.0        ] [2024-07-22T11:21:41,814051+00:00]";

  test(s1);
  test(s2);
  test(s3);
}

输出

<[8] [13420] [    ] [        ] [pts/3       ] [                    ] [0.0.0.0        ] [2024-07-22T11:18:29,836564+00:00]>
  0:<8>
  1:<13420>
  2:<>
  3:<>
  4:<pts/3>
  5:<>
  6:<0.0.0.0>
  7:<2024-07-22T11:18:29,836564+00:00>
<[7] [13611] [ts/3] [john    ] [pts/3       ] [192.168.1.38        ] [192.168.1.38   ] [2024-07-22T11:21:30,065856+00:00]>
  0:<7>
  1:<13611>
  2:<ts/3>
  3:<john>
  4:<pts/3>
  5:<192.168.1.38>
  6:<192.168.1.38>
  7:<2024-07-22T11:21:30,065856+00:00>
<[8] [13611] [    ] [        ] [pts/3       ] [                    ] [0.0.0.0        ] [2024-07-22T11:21:41,814051+00:00]>
  0:<8>
  1:<13611>
  2:<>
  3:<>
  4:<pts/3>
  5:<>
  6:<0.0.0.0>
  7:<2024-07-22T11:21:41,814051+00:00>

此代码任务的优点是该行可能是可写的,因此通过添加空字符将标记化字段保存在该行中。 这可以避免缓冲区溢出问题。

© www.soinside.com 2019 - 2024. All rights reserved.