如何用C语言从getline读取的缓冲区中逐个提取字符串?
解决逐行提取字母数字单词并记录行号的问题
问题根源
直接重复调用sscanf(buffer, "%[a-zA-Z_0-9]", word)只会从缓冲区起始位置读取,所以每次都拿到第一个单词。要实现逐个提取,必须跟踪当前读取的位置,让下一次读取从上次结束的位置开始。
方案一:用指针+sscanf的%n参数
%n是sscanf的特殊格式符,会记录本次调用实际读取的字符数。结合指针移动,可以逐次定位到下一个单词的起始位置:
#include <stdio.h> #include <ctype.h> #include <string.h> int main() { FILE *fp = fopen("entry.txt", "r"); if (!fp) { perror("Failed to open file"); return 1; } char *buffer = NULL; size_t buf_size = 0; int currentLine = 0; while (getline(&buffer, &buf_size, fp) != -1) { currentLine++; char *ptr = buffer; char word[256]; // 根据需求调整单词最大长度 int n; while (1) { // 跳过所有非字母数字/下划线的字符 while (*ptr && !isalnum((unsigned char)*ptr) && *ptr != '_') { ptr++; } if (!*ptr) break; // 到行尾,退出循环 // 读取当前单词,同时记录读取的字符数到n if (sscanf(ptr, "%[a-zA-Z_0-9]%n", word, &n) == 1) { printf("Line %d: %s\n", currentLine, word); ptr += n; // 移动指针到本次读取结束的位置 } else { break; } } } free(buffer); fclose(fp); return 0; }
方案二:用strtok_r(可重入版字符串分割)
strtok_r是线程安全的分割函数,适合逐行处理场景。需要指定所有非目标字符作为分隔符:
#include <stdio.h> #include <string.h> int main() { FILE *fp = fopen("entry.txt", "r"); if (!fp) { perror("Failed to open file"); return 1; } char *buffer = NULL; size_t buf_size = 0; int currentLine = 0; char *saveptr; // strtok_r的保存指针,用于跟踪每行的分割位置 while (getline(&buffer, &buf_size, fp) != -1) { currentLine++; // 替换换行符为'\0',避免分割时把换行符当成字符 buffer[strcspn(buffer, "\n")] = '\0'; // 分割字符串,分隔符为所有非字母数字/下划线的字符 char *word = strtok_r(buffer, " ,.!@#$%^&*()+-=[]{}|\\;:'\"<>/?", &saveptr); while (word != NULL) { printf("Line %d: %s\n", currentLine, word); word = strtok_r(NULL, " ,.!@#$%^&*()+-=[]{}|\\;:'\"<>/?", &saveptr); } } free(buffer); fclose(fp); return 0; }
注意事项
- 方案一中的
isalnum需要包含<ctype.h>,并且要把字符转为unsigned char,避免处理负数值字符(如扩展ASCII)时出错。 - 方案二中的分隔符集合需要根据实际需求补充所有需要过滤的特殊字符。
- 要注意单词的最大长度,避免缓冲区溢出(比如方案一中的
word[256],如果有超长单词需要调整或动态分配内存)。
内容的提问来源于stack exchange,提问作者Educg550
相关产品推荐
相关产品推荐

