好的,sscanf() 是C语言中一个非常强大的输入解析函数,除了基本的 %d, %s, %f 之外,它还有许多高级的格式说明符。这些语法可以让你用非常简洁的方式处理复杂的字符串解析任务。
以下是一些非常有用且类似 %*[^AV] 的高级语法,我将为每个都提供解释和简单的例子。
1. 赋值抑制符 *
- 作用:读取数据并根据转换说明符进行解析,但丢弃结果,不将其赋值给任何变量。这用于跳过输入中不需要的部分。
- 语法:在
%后直接跟*,例如%*d,%*s,%*[^,]。
示例:跳过日期中的 day
#include <stdio.h>
int main() {
char date[] = "2024-06-02";
int year, month;
// 使用 %*d 来跳过“日”的部分,不将其存储到变量中
sscanf(date, "%d-%d-%*d", &year, &month);
printf("Year: %d, Month: %d\n", year, month); // 输出: Year: 2024, Month: 6
return 0;
}
2. 扫描集 [...] 和反向扫描集 [^...]
这是最强大的功能之一,用于匹配一个字符集合。
%[aeiou]:读取仅包含在方括号内字符的字符串,直到遇到第一个不在集合中的字符为止。%[^aeiou]:读取不包含在方括号内字符的字符串,直到遇到第一个在集合中的字符为止(^表示“非”)。
示例1:提取一个单词(直到遇到逗号)
#include <stdio.h>
int main() {
char data[] = "Hello,World";
char first_word[20];
// 读取直到遇到逗号(不包含逗号)
sscanf(data, "%[^,]", first_word);
printf("First word: %s\n", first_word); // 输出: First word: Hello
return 0;
}
示例2:提取所有数字
#include <stdio.h>
int main() {
char str[] = "Price: 123USD";
char digits[20];
// 读取所有是数字的字符
sscanf(str, "%*[^0-9]%[0-9]", digits); // 先跳过非数字,再读取数字
printf("Digits: %s\n", digits); // 输出: Digits: 123
return 0;
}
3. 宽度限定符
- 作用:指定从输入中读取的最大字符数。这对于防止缓冲区溢出(一种常见的安全漏洞)至关重要。
- 语法:在
%和转换符之间加入一个数字,例如%5s,%10[^,]。
示例:安全地读取字符串,防止溢出
#include <stdio.h>
int main() {
char input[] = "ThisIsALongString";
char safe_buffer[6]; // 只能容纳5个字符 + '\0'
// 只从输入中读取最多5个字符
sscanf(input, "%5s", safe_buffer);
printf("Safe content: '%s'\n", safe_buffer); // 输出: Safe content: 'ThisI'
return 0;
}
**4. 获取已读取的字符数 %n
- 作用:不消耗输入,而是将到当前位置为止已成功读取的字符数量存储到一个整型变量中。这对于复杂格式的解析和调试非常有用。
- 注意:
%n的行为在某些上下文中存在争议,但在sscanf中使用是安全且明确的。
示例:计算读取位置
#include <stdio.h>
int main() {
char data[] = "123 456 789";
int a, b, count_pos;
// 读取两个整数,并在读取第二个后记录位置
sscanf(data, "%d %d%n", &a, &b, &count_pos);
printf("a=%d, b=%d\n", a, b); // 输出: a=123, b=456
printf("Number of characters read up to 'b': %d\n", count_pos);
// 输出: Number of characters read up to 'b': 7 (即 "123 456" 的长度)
return 0;
}
综合实战示例
假设有一个复杂的字符串,我们需要从中提取多种信息:
#include <stdio.h>
int main() {
// 一个日志条目
char log_entry[] = "INFO [2024-06-02 10:30:25] User:Alice connected from 192.168.1.1";
char log_level[10];
char date[12];
char time[9];
char username[20];
char ip_addr[16];
int chars_processed;
// 分解格式:
// 1. %[^ ] : 读取直到空格(级别"INFO")
// 2. %*[[] : 跳过直到(包括)'['字符
// 3. %10[^ ] : 读取最多10个字符直到空格(日期)
// 4. %*1s : 跳过1个空格
// 5. %8[^]] : 读取最多8个字符直到']'(时间)
// 6. %*[^:]: : 跳过直到":"
// 7. %19[^ ] : 读取最多19个字符直到空格(用户名)
// 8. %*[^0123456789.] : 跳过直到遇到数字或点(IP地址开始)
// 9. %15[0-9.] : 读取IP地址(数字和点)
// 10. %n : 获取总共处理了多少字符
sscanf(log_entry, "%[^ ] %*[[]%10[^ ] %*1s%8[^]]%*[^:]: %19[^ ] %*[^0123456789.]%15[0-9.]%n",
log_level, date, time, username, ip_addr, &chars_processed);
printf("Level: %s\n", log_level);
printf("Date: %s\n", date);
printf("Time: %s\n", time);
printf("User: %s\n", username);
printf("IP: %s\n", ip_addr);
printf("Total characters parsed: %d\n", chars_processed);
return 0;
}
输出:
Level: INFO
Date: 2024-06-02
Time: 10:30:25
User: Alice
IP: 192.168.1.1
Total characters parsed: 62
总结与注意事项
|
语法 |
用途 |
示例 |
|
|
跳过匹配项,不赋值 |
|
|
|
读取只包含指定字符的字符串 |
|
|
|
读取直到遇到指定字符的字符串 |
|
|
|
指定读取的最大宽度(防溢出) |
|
|
|
获取已读取的字符数 |
|
重要提示:
- 安全性:始终使用宽度限定符(如
%19s而不是%s)来防止缓冲区溢出攻击。 - 返回值: always check the return value of
sscanf(). It returns the number of successfully assigned items, which is crucial for error handling. - 复杂性:虽然强大,但过于复杂的
sscanf格式字符串会难以阅读和维护。有时使用strtok或手动解析循环可能是更清晰的选择。
掌握这些语法能让你在C语言中轻松应对大多数字符串解析挑战。



900

被折叠的 条评论
为什么被折叠?



