下面的代码:
#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。有办法吗?
确实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)