使用 sscanf 获取零个或多个长度的字符串

ham*_*idi 2 c scanf

下面的代码:

#include <stdio.h>

int main(void) {
  char buf[80] = "salam";
  const char *fmt = "\"%79[^\"]\"";
  int n;

  n = sscanf("\"\"", fmt, buf);
  printf("%d fields were read. buf = '%s'\n", n, buf);
  n = sscanf("\"hamidi\"", fmt, buf);
  printf("%d fields were read. buf = '%s'\n", n, buf);
}
Run Code Online (Sandbox Code Playgroud)

输出:

已读取 0 个字段。buf = 'salam'
已读取 1 个字段。buf = '哈米迪'

这表明 sscanf 函数无法读取具有指定格式字符串的空字符串。是否有一个很好的替代正则表达式格式字符串来通过 sscanf 函数读取长度为零到最多 79 个字符的字符串?换句话说,我希望第一个 sscanf 将 '\0' 插入 buf[0] 并返回 1 而不是 0。有办法吗?

chq*_*lie 6

确实sscanf,朋友不能处理空字段,也不能strtok。标准库中没有直接的替代方案,但您可以使用循环或使用strchr,strpbrk或编写一个简单的扫描器strcspn

这是一个简单的例子:

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

int scan_string(char *dest, size_t size, const char *src, const char **endp) {
    if (*src++ != '"') {
        // no string delimiter
        return 0;
    }
    size_t len = strcspn(src, "\"");
    if (src[len] != '"') {
        // no matching string delimiter
        return 0;
    }
    if (endp) {
        *endp = src + len + 1;
    }
    if (size > 0) {
        if (len >= size)
            len = size - 1;
        memcpy(dest, src, len);
        dest[len] = '\0';
    }
    return 1;
}

void test(const char *src) {
    char buf[80] = "<unchanged>";
    const char *end = "<unchanged>";
    int n = scan_string(buf, sizeof buf, src, &end);
    printf("src: '%s', n: %d, buf: '%s', end: '%s'\n",
           src, n, buf, end);
}

int main(void) {
    test("");
    test("\"");
    test("\"\"");
    test("''");
    test("\"hamidi\"");
    test("\"Hello\" \"world\"");
    test("\"\\\"\"");
    test("\"Hello world\\n\"");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

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

int scan_string(char *dest, size_t size, const char *src, const char **endp) {
    if (*src++ != '"') {
        // no string delimiter
        return 0;
    }
    size_t len = strcspn(src, "\"");
    if (src[len] != '"') {
        // no matching string delimiter
        return 0;
    }
    if (endp) {
        *endp = src + len + 1;
    }
    if (size > 0) {
        if (len >= size)
            len = size - 1;
        memcpy(dest, src, len);
        dest[len] = '\0';
    }
    return 1;
}

void test(const char *src) {
    char buf[80] = "<unchanged>";
    const char *end = "<unchanged>";
    int n = scan_string(buf, sizeof buf, src, &end);
    printf("src: '%s', n: %d, buf: '%s', end: '%s'\n",
           src, n, buf, end);
}

int main(void) {
    test("");
    test("\"");
    test("\"\"");
    test("''");
    test("\"hamidi\"");
    test("\"Hello\" \"world\"");
    test("\"\\\"\"");
    test("\"Hello world\\n\"");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是一个稍微复杂的版本,处理一些\序列和不同的分隔符:

int scan_string(char *dest, size_t size, const char *src, const char **endp) {
    char sep = *src++;
    char ch;
    size_t i = 0;

    // handle both single and double quotes
    if (sep != '"' && sep != '\'')
        return 0;
    while ((ch = *src++) != sep) {
        if (ch == '\0') {
            if (i < size)
                dest[i] = '\0';
            return 0;
        }
        if (ch == '\\' && *src != '\0') {
            switch (ch = *src++) {
            case 'f': ch = '\f'; break;
            case 'n': ch = '\n'; break;
            case 'r': ch = '\r'; break;
            case 't': ch = '\t'; break;
            case 'v': ch = '\v'; break;
            // handle octal and hex sequences...
            default: ch = *src++; break;
            }
        }
        if (i + 1 < size)
            dest[i++] = ch;
    }
    if (i < size)
        dest[i] = '\0';
    if (endp)
        *endp = src;
    return 1;
}
Run Code Online (Sandbox Code Playgroud)

输出:

src: '', n: 0, buf: '<unchanged>', end: '<unchanged>'
src: '"', n: 0, buf: '<unchanged>', end: '<unchanged>'
src: '""', n: 1, buf: '', end: ''
src: '''', n: 0, buf: '<unchanged>', end: '<unchanged>'
src: '"hamidi"', n: 1, buf: 'hamidi', end: ''
src: '"Hello" "world"', n: 1, buf: 'Hello', end: ' "world"'
src: '"\""', n: 1, buf: '\', end: '"'
src: '"Hello world\n"', n: 1, buf: 'Hello world\n', end: ''
Run Code Online (Sandbox Code Playgroud)