【问题标题】:string parsing in C - string with fomat specifiers [closed]C中的字符串解析-带有格式说明符的字符串[关闭]
【发布时间】:2018-05-17 08:30:19
【问题描述】:

我得到一个日志文件,其中包含看起来像

的日志数据
system%s disconnected: IP%s %s:%s,"1","100.100.100.100","port","1000"
Login by user %s,"TestUserName"
connecting to system%s,"29" 
Newlog by %s on %s,"TestUser2","Wednesday"

我需要转换成哪个,

system1 disconnected: 100.100.100.100 port 1000
Login by user TestUserName
connecting to system29
Newlog by TestUser2 on Wednesday

到目前为止,我已将此字符串拆分为 2 个字符串,第 1 部分将包含带有格式说明符的字符串,第 2 部分将包含带有信息/数据的字符串。 例如:

1)
part1 = system%s disconnected: IP%s %s:%s
part2 =  "1","100.100.100.100","port","1000"

2) 
part1 = Login by user %s
part2 = "TestUserName"

3)
part1 = connecting to system%s
part2 = "29" 

我想用 sprintf 来得到想要的输出,

sprintf(testString,"%s,%s", part1, part2);
printf(testString); //This doesn't work.

printf("system%s disconnected: IP%s %s:%s","1","100.100.100.100","port","1000"); //This works, but not sure of getting here

【问题讨论】:

  • 有一组与printf相关的函数,其名称以v开头,例如vsprintf,如果您事先不知道参数的数量,这很有用。跨度>
  • 如果您只有 %s(no%i、%d 等...),您可以循环并用第 2 部分中的 n 元素替换 n %s
  • 谢谢。我也可能得到 %i(或)%d。
  • 然后类似于%[a-Z] 正则表达式模式与',' 上的part2 拆分相结合可能会帮助您进行替换。正如@ArndtJonasson 所提到的,可能已经有一些功能可以做到这一点
  • @ArndtJonasson 谢谢,我正在努力寻找这些功能。

标签: c string c-strings


【解决方案1】:

我使用 strtok 将由 ',' 分隔的行标记为标记。我编写了非常简单的函数来从字符串中删除前导撇号和结束撇号。解析函数可能需要重写以更好地处理字符串中的“,”(尝试ao_string_tokenize)。以下程序:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <assert.h>
#define DBG(...) do;while(0) 
//#define DBG(...) fprintf(stderr, __VA_ARGS__)
char *remove_leading_and_closing_apostrophe(char *str)
{
    if (str == NULL) 
        return str;
    if (str[0] == '"')
        ++str;
    size_t strleng = strlen(str);
    if (str[strleng - 1] == '"')
        str[strleng - 1] = '\0';
    return str;
}
int main()
{
    const char s[2] = ",";
    char line[200];
    const char *args[7];
    size_t argscnt = 0;
    while (fgets(line, 200, stdin) != NULL) {
        // remove newline
        assert(line[strlen(line)-1] == '\n');
        line[strlen(line)-1] = '\0';

        DBG("@ read line '%s'\n", line);

        argscnt = 0;
        args[argscnt] = strtok(line, s);
        assert(args[argscnt] != NULL); // not handled correctly
        DBG("@ read arg[%zu]='%s'\n", argscnt, args[argscnt]);
        argscnt++;
        assert(argscnt <= sizeof(args)/sizeof(args[0]));
        while (args[argscnt-1] != NULL) {
            args[argscnt] = remove_leading_and_closing_apostrophe(strtok(NULL, s));
            DBG("@ read arg[%zu]='%s'\n", argscnt, args[argscnt]);
            argscnt++;
            assert(argscnt <= sizeof(args)/sizeof(args[0]));
        }
        argscnt--; // incremented one time too much, FIXME

        const char * const * const a = args; // just shorter name
        // This is the most portable way.
        switch(argscnt) {
        case 0: break;
        case 1: printf(a[0]); break;
        case 2: printf(a[0],a[1]); break;
        case 3: printf(a[0],a[1],a[2]); break;
        case 4: printf(a[0],a[1],a[2],a[3]); break;
        case 5: printf(a[0],a[1],a[2],a[3],a[4]); break;
        case 6: printf(a[0],a[1],a[2],a[3],a[4],a[5]); break;
        case 7: printf(a[0],a[1],a[2],a[3],a[4],a[5],a[6]); break;
        default: assert(0); break;
        }
        puts("");
    }
    return 0;
}

对于 stdin 上的以下输入(格式正确,末尾有空换行符):

system%s disconnected: IP%s %s:%s,"1","100.100.100.100","port","1000"
Login by user %s,"TestUserName"
connecting to system%s,"29"
Newlog by %s on %s,"TestUser2","Wednesday"

产生以下输出:

system1 disconnected: IP100.100.100.100 port:1000
Login by user TestUserName
connecting to system29
Newlog by TestUser2 on Wednesday

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-25
    • 1970-01-01
    • 2017-08-04
    • 2011-06-19
    相关资源
    最近更新 更多