如何捕获sscanf'd字符串的长度?

时间:2010-12-09 03:49:14

标签: c++ c string parsing scanf

我正在解析一个遵循可预测模式的字符串:

  1. 1个字符
  2. 一个整数(一个或多个数字)
  3. 1冒号
  4. 一个字符串,其长度来自#2
  5. 例如:

    s5:stuff
    

    我可以很容易地看到如何用PCRE等来解析它,但为了速度,我宁愿坚持使用普通的字符串操作。

    我知道我需要分两步完成,因为在知道其长度之前我无法分配目标字符串。我的问题是优雅地获得所述字符串的 start 的偏移量。一些代码:

    unsigned start = 0;
    char type = serialized[start++]; // get the type tag
    int len = 0;
    char* dest = NULL;
    char format[20];
    //...
    switch (type) {
      //...
      case 's':
        // Figure out the length of the target string...
        sscanf(serialized + start, "%d", &len);
        // <code type='graceful'>
        // increment start by the STRING LENGTH of whatever %d was
        // </code>
        // Don't forget to skip over the colon...
        ++start;
        // Build a format string which accounts for length...
        sprintf(format, "%%%ds", len);
        // Finally, grab the target string...
        sscanf(serialized + start, format, string);
        break;
      //...
    }
    

    这段代码大致取自我所拥有的(由于手头的问题而无法完成),但它应该得到重点。也许我完全采取了错误的做法。 最优雅的方法是什么?解决方案可以是C或C ++(如果有足够的响应,我实际上希望看到竞争方法。)

6 个答案:

答案 0 :(得分:8)

您可以使用%n转换说明符,它不使用任何输入 - 而是需要int *参数,并将输入中消耗的字符数写入其中:

int consumed;

sscanf(serialized + start, "%d%n", &len, &consumed);
start += consumed;

(但不要忘记检查sscanf()返回&gt; 0!)

答案 1 :(得分:1)

使用%n格式说明符将到目前为止读取的字符数写入整数参数。

答案 2 :(得分:1)

这是一个C ++解决方案,它可能更好,并且专门用于处理您的示例输入的硬编码,但不需要太多修改才能正常工作。

std::stringstream ss;

char type;
unsigned length;
char dummy;
std::string value;

ss << "s5:Helloxxxxxxxxxxx";

ss >> type;
ss >> length;
ss >> dummy;
ss.width(length);
ss >> value;

std::cout << value << std::endl;

声明:

我是C ++的菜鸟。

答案 3 :(得分:0)

你可能只是使用会忽略冒号的atoi。

e.g。 len = atoi(序列化+开始);

atoi唯一的一点是,如果它返回零,则可能意味着转换失败,或者长度真的为零。所以它并不总是最合适的功能。

答案 4 :(得分:0)

如果用空格替换你的冒号,scanf会停在它上面,你可以得到大小为malloc的大小,然后运行另一个scanf来得到其余的字符串。

int main (int argc, const char * argv[]) {
char foo[20];
char *test;

scanf("%s",foo); //"hello world"
printf("foo = %s\n", foo);//prints hello
//get size
    test = malloc(sizeof(char)* 10);//replace 10 with your string size
    scanf("%s", test);
printf("test = %s\n", test);//prints world

return 0;
}

`

答案 5 :(得分:0)

似乎格式过于规范......(使用可变长度字段指定可变长度字段的长度)。

如果您正在使用GCC,我建议

if (sscanf(serialized,"%c%d:%as",&type,&len,&dest)<3) return -1;
/* use type, dest; ignore len */
free(dest);
return 0;