strtok 跳过多个定界符,如何让它只跳过一个

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

我目前正在为 nmea 句子开发一个解析器,通常是这样的:

"$GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62\r\n"

所以我创建了这个函数,它使用 strtok 来解析它,使用逗号作为分隔符并将每个数据字段存储在值数组中,重要的是每个数据字段都进入数组中的正确位置。

int split_string_by_comma (nmea_message_t * message_info, char ** values)
{
    int i = 0;
    char * p = strtok(message_info->data_field, MSG_DELIMITER);
    
    while (p != NULL)
    {
        values[i++] = p;
        p = strtok(NULL, MSG_DELIMITER);
    }
    return i;
}

问题是,nmea 语句跳过某些数据字段的情况并不少见,例如:

"$GPRMC,,A,,S,14507.36,E,000.0,,,,E*62\r\n"

在这种情况下,我的函数是无用的,因为我希望逗号之间的空数据字段被分配为 NULL 值,而不是被完全忽略。

有什么建议吗? 谢谢!

c strtok string.h
2个回答
2
投票

strsep
可能是你想要的:

引入 strsep() 函数作为 strtok(3) 的替代品,
因为后者不能处理空字段。
然而,strtok(3) 符合 C89/C99,因此更便携。

它的语法不完全一样:

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

#define MSG_DELIMITER ","

void split_string_by_comma (char* msg)
{
    int i = 0;
    char * p = strsep(&msg, MSG_DELIMITER);

    while (p != NULL)
    {
        printf("%d - %s\n", ++i, p);
        p = strsep(&msg, MSG_DELIMITER);
    }    
}

int main(void)
{
    char good[] = "$GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62\r\n";
    char bad[] = "$GPRMC,,A,,S,14507.36,E,000.0,,,,E*62\r\n";

    split_string_by_comma(good);
    split_string_by_comma(bad);
    return 0;
}

:~/test/strsep$ ./a.out
1 - $GPRMC
2 - 081836
3 - A
4 - 3751.65
5 - S
6 - 14507.36
7 - E
8 - 000.0
9 - 360.0
10 - 130998
11 - 011.3
12 - E*62

1 - $GPRMC
2 -
3 - A
4 -
5 - S
6 - 14507.36
7 - E
8 - 000.0
9 -
10 -
11 -
12 - E*62

0
投票

这是

strsep()
的替代方案,我正在开发一个不可用的系统。使用
strtok_r()
来自上一个调用的剩余指针地址和从当前调用开始的标记化地址可以识别是否跳过了任何额外的定界符。

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

#define MAX_TOKENS    15
#define MAX_TOKEN_LEN 20

int main()
{
    
    char tokens[MAX_TOKENS][MAX_TOKEN_LEN] = { 0 };
    char str[] = "This,is,a,string,,to,be,,,split,on,comma";
    
    char *leftover;
    unsigned long leftover_addr_start = (unsigned long)str; // Save leftover start
    const char *token = strtok_r(str, ",", &leftover);
    int total_tokens = 0;
    
    do {
        unsigned long token_addr = (unsigned long)token; // Token start address
        
        if(token_addr != leftover_addr_start) { // Extra delimiters encountered
        
            unsigned long num_extra_delm = 
                  (unsigned long)(token_addr - leftover_addr_start);
            
            printf("%lu Extra delimiter(s) encountered between '%s' and '%s'\n", 
                   num_extra_delm, tokens[total_tokens-1], token);
        }
        
        (void)strncpy(tokens[total_tokens], token, MAX_TOKEN_LEN); // Save Token
        printf("Tokenized - '%s'\n", tokens[total_tokens]);
        
        total_tokens++;                               // Increase Token count
        leftover_addr_start = (unsigned long)leftover; // Save leftover start address
        
    } while((token = strtok_r(NULL, ",", &leftover)) && total_tokens < MAX_TOKENS);

    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.