【问题标题】:Parse a string in C89/C90在 C89/C90 中解析字符串
【发布时间】:2020-07-22 20:58:10
【问题描述】:

解析字符串

char* "AS LSLDS SAAL SS"

【问题讨论】:

    标签: c string parsing scanf c89


    【解决方案1】:

    为什么不简单地使用sscanf 字符类格式说明符 "%[^\n]" 来读取名称,例如

        if (sscanf (str, "%7s %7s %d %63[^\n]", loc, dir, &len, name))
            printf ("loc : %s\ndir : %s\nlen : %d\nname: %s\n", loc, dir, len, name);
    

    field-width 修饰符必须与任何字符串转换一起使用,否则sscanf 并不比gets() 好。宽度将对应于以下声明,例如

        char str[] = "D4 E 3 NullByte Sub", 
            loc[8], dir[8], name[64];
        int len;
    

    一个完整的例子是:

    #include <stdio.h>
    
    int main (void) {
    
        char str[] = "D4 E 3 NullByte Sub", 
            str2[] = "D4 E 3 NullByte Sub Ship Barrier",
            loc[8], dir[8], name[64];
        int len;
    
        if (sscanf (str, "%7s %7s %d %63[^\n]", loc, dir, &len, name))
            printf ("\nloc : %s\ndir : %s\nlen : %d\nname: %s\n", loc, dir, len, name);
    
        if (sscanf (str2, "%7s %7s %d %63[^\n]", loc, dir, &len, name))
            printf ("\nloc : %s\ndir : %s\nlen : %d\nname: %s\n", loc, dir, len, name);
    }
    

    使用/输出示例

    $ ./bin/sscanf_loc-dir-name
    
    loc : D4
    dir : E
    len : 3
    name: NullByte Sub
    
    loc : D4
    dir : E
    len : 3
    name: NullByte Sub Ship Barrier
    

    【讨论】:

    • 您假设名称中永远不会有换行符,但问题中没有任何内容可以支持该假设。
    • 你是完全正确的——这是我所做的一个假设,它完全得到char [128] = "D4 E 3 NullByte Sub";line = "D4 E 3 NullByte Sub Ship Barrier"的支持——它们都不能包含嵌入的'\n'
    【解决方案2】:

    问题在于scanf%s 格式(以及sscanf 等相关函数)读取的是空格分隔 字符串。

    由于字符串中没有良好的“记录结束”标记(超出字符串的实际结尾),因此很难使用 sscanf,即使使用其特殊的 %[ 格式说明符。

    相反,我建议您了解strtok 以及如何使用它来“标记”字符串。

    有了它,您可以执行以下操作:

    char *p = strtok(line, " ");
    strcpy(location, p);
    
    p = strtok(NULL, " ");
    strcpy(direction, p);
    
    p = strtok(NULL, " ");
    length = strtol(p, NULL, 10);
    
    strcpy(name, p + strlen(p) + 1);  // p + strlen(p) skips over the number, +1 to skip over the space as well
    

    【讨论】:

    • 现在我认真考虑了这一点,p + strlen(p) + 1 是对的,但它看起来超级粗略。
    【解决方案3】:

    像这样:

    int offset;
    sscanf(line, "%s %s %d %n", location, direction, &length, &offset);
    name = line + offset; // or strncpy or something, if you want a new string instead of just a pointer into the old one
    

    %n 记录到目前为止已经消耗了多少个字符。如果你向前跳转那么多字符,那么你会得到字符串的其余部分。

    旁注:在没有最大字段宽度的情况下使用%s(或让它使用m 修饰符自行分配)是危险的,除非你100% 确定你永远不会得到一个过长的单词。

    【讨论】:

      猜你喜欢
      • 2017-05-23
      • 1970-01-01
      • 1970-01-01
      • 2010-11-07
      • 2016-01-04
      • 2012-01-07
      • 2011-06-20
      • 2010-10-11
      • 2017-10-12
      相关资源
      最近更新 更多