【问题标题】:Parsing substrings from a string with "sscanf" function in C在 C 中使用“sscanf”函数从字符串中解析子字符串
【发布时间】:2016-05-15 16:04:54
【问题描述】:

我有一个如下所示的 gps 字符串:

char gps_string[] = "$GPRMC,080117.000,A,4055.1708,N,02918.9336,E,0.00,316.26,00,,,A*78";

我想解析逗号之间的子字符串,如下所示:

$GPRMC
080117.000
A
4055.1708
.
.
.

我已经尝试过如下的 sscanf 函数:

 sscanf(gps_string,"%s,%s,%s,%s,%s,",char1,char2,char3,char4,char5);

但这不起作用。如果使用上述函数,char1 数组将获取整个字符串。

实际上,我在之前的算法中使用了 strchr 函数并让它工作,但如果我可以让它与 sscanf 一起工作并在子字符串中获取这些参数,它会更容易和更简单。

顺便说一句,逗号之间的子字符串可能会有所不同。但是逗号顺序是固定的。例如下面是另一个 gps 字符串示例,但由于卫星问题,它不包含它的某些部分:

char gps_string[] = "$GPRMC,001041.799,V,,,,,0.00,0.00,060180,,,N*"

【问题讨论】:

  • 使用strtok()分割字符串
  • 以上两个cmets是很好的解决方案但是strstr不是。
  • @abdullahcinar:您需要阅读有关 scanf 函数的文档。但是[^,] 匹配每个不是逗号的字符。
  • 另一种方法是使用strpbrk() 查找下一个','。如果这样做,您将编写循环以获取子字符串并更新指针以查找下一个逗号。其他线程上的一些 cmets 提到了这一点,以避免 strtok() 的一些问题

标签: c arrays string parsing substring


【解决方案1】:

其他答案中有许多 cmets 指出 strtok() 存在许多问题,并建议改用 strpbrk()。可以在Arrays and strpbrk in C

找到如何使用它的示例

我没有可用的编译器,因此无法对此进行测试。我的代码中可能存在拼写错误或其他错误,但我相信您可以弄清楚其中的含义。

在这种情况下,您将使用

char *String_Buffer = gps_string;
char *start = String_Buffer;
char *end;
char *fields[MAXFIELDS];
int i = 0;
int n = 0;
char *match = NULL;

while (end = strpbrk(start, ",")) // Get pointer to next delimiter 
{
  /* found it, allocate enough space for it and NUL */
  /* If there ar two consecutive delimiters, only the NUL gets entered */
  n = end - start;
  match = malloc(n + 1);

  /* copy and NUL terminate */
  /* Note that if n is 0, nothing will be copied so do not need to test */
  memcpy(match, start, n);
  match[n] = '\0';

  printf("Found field entry: %s\n", match);
  /* Now save the actual match string pointer into the fields array*/
  /* Since the match pointer is in fields, it does not need to be freed */
  fields[i++] = match;
  start = end + 1;
}

/* Check that the last element in the gps_string is not ,
   Then get the final field, which has the NUL termination of the string */
  n = strlen(start);
  match = malloc(n + 1);
  /* Note that if n is 0, only the terminator will be put in */
  strcpy(match, start);
  printf("Found field entry: %s\n", match);
  fields[i++] = match;
  printf("Total number of fields: %d\n", i);

【讨论】:

  • 好奇:使用strncpy(match, start, n)memcpy(match, start, n) 作为代码已知复制的任何特定原因将停止在n 而不是'\0'
  • 没有特别的原因。我只是碰巧使用strncpy()。我想是因为我在处理字符串时倾向于想到strcpy()。实际上,我知道子字符串中没有 '\0'。不过好点。我会改的。
  • @chux 抱歉忘记了 ping。我将代码更改为使用memcpy()。只是习惯于使用strcpy() 来输入让我输入strncpy() 的字符串
  • @abdullahcinar 我刚刚意识到我忘记将下一个分隔符 find 放入 while。没有它,这将是一个无限循环。对此感到抱歉
【解决方案2】:

你可以使用strtok:

#include <stdio.h>

int main(void) {
    char gps_string[] = "$GPRMC,080117.000,A,4055.1708,N,02918.9336,E,0.00,316.26,00,,,A*78";
    char* c = strtok(gps_string, ",");
    while (c != NULL) {
        printf("%s\n", c);
        c = strtok(NULL, ",");
    }
    return 0;
}

编辑:正如 Carey Gregory 提到的,strtok 修改了给定的字符串。这在我链接到的手册页中有说明,您也可以找到一些详细信息here

【讨论】:

  • 感谢您的回答,这非常有效。使用 sscanf 怎么样?使用您提到的 strtok 或使用 sscanf 作为 user3121023 答案中我的更正版本之间有什么区别?
  • 我猜 user3121023 已经删除了他的答案:/ 这是他的建议,这也有效:sscanf(gps_string,"%[',],%[',],%[',],%[',],%[',]",char1,char2,char3,char4,char5);
  • manual 说“解析字符串中两个或多个连续分隔符的序列被认为是一个分隔符” OP 说在最后的示例中可能会出现这种情况。
  • @abdullah cinar "%[',],%[',],%[',],%[',],%[',]" 不起作用。你的意思是"%[^,],%[^,],%[^,],%[^,],%[^,]"?这对于连续的,, 也有问题,因此不是一个好的解决方案。
  • 是的,对不起,我是这个意思。但是我没有尝试连续,,所以,我可以寻找其他选项。
猜你喜欢
  • 1970-01-01
  • 2020-04-28
  • 1970-01-01
  • 2013-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多