如何使用scanf()提取URL域名后缀并实现数组匹配索引查询?
嘿,这个问题问得好!咱们直接说结论:用scanf()能实现针对简单场景的提取,但它的局限性很大,处理复杂URL时容易出错。如果你的URL格式比较固定(比如最多三个点,像www.xxx.com或www.xxx.com.tr这种),可以凑合用;但如果要应对各种不规则的URL,还是用字符串处理函数(比如strrchr、strtok这类)更稳妥。
先看scanf()的实现思路
scanf()的核心是靠格式控制符来匹配和提取内容,咱们可以利用%*[^.]来跳过任意非.的字符,%*c跳过.本身,然后精准抓取我们想要的部分。
但这里有个问题:你给出的两个例子格式不一样——一个是两个点的www.stackoverflow.com,要提取最后一个.后的com;另一个是三个点的www.google.com.tr,要提取倒数第二个.和最后一个.之间的com。纯scanf很难同时兼容这两种情况,因为它是按顺序匹配的,必须预先知道URL的结构(比如有几个点),不然匹配会出错:
- 用
%*[^.]%*c%*[^.]%*c%s的话,www.stackoverflow.com能正确提取com,但www.google.com.tr会读取到com.tr,不符合需求; - 换用
%*[^.]%*c%*[^.]%*c%[^.]%*c%s,只能提取www.google.com.tr里的com,但对www.stackoverflow.com会匹配失败,因为没有足够的.。
所以纯scanf只能处理固定格式的URL,得结合额外逻辑(比如先统计点的数量)才能勉强兼容你的示例场景,灵活性很差。
更靠谱的方案:结合字符串函数
既然你本来就打算写函数实现,那不如直接用C标准库的字符串函数,逻辑更清晰,也能处理更多场景。比如这个思路:
- 从右往左找第一个
.(也就是最后一个点),记为last_dot; - 再从
last_dot的左边找前一个.,记为prev_dot; - 如果
prev_dot存在(URL至少两个点),提取prev_dot+1到last_dot之间的内容;如果不存在(只有一个点),提取last_dot+1到结尾的内容; - 把提取到的后缀和你的数组匹配,返回索引或-1。
给你写个示例代码:
#include <stdio.h> #include <string.h> // 匹配后缀的数组 const char* suffixes[] = {"com", "org", "net", "edu"}; const int suffix_count = sizeof(suffixes)/sizeof(suffixes[0]); int findSuffixIndex(const char* url) { // 找最后一个点 char* last_dot = strrchr(url, '.'); if (!last_dot) return -1; // 没有点,无效URL // 找倒数第二个点 char* prev_dot = strrchr(url, '.'); if (prev_dot == last_dot) { prev_dot = strrchr(url, '.', last_dot - url - 1); } char* target_suffix; // 临时截断字符串,方便提取 char original_char = *last_dot; if (prev_dot) { target_suffix = prev_dot + 1; *last_dot = '\0'; } else { target_suffix = last_dot + 1; } // 遍历数组匹配 int index = -1; for (int i = 0; i < suffix_count; i++) { if (strcmp(target_suffix, suffixes[i]) == 0) { index = i; break; } } // 恢复原URL的字符 if (prev_dot) *last_dot = original_char; return index; } int main() { char url[256]; printf("输入URL:"); fgets(url, sizeof(url), stdin); // 去掉fgets带来的换行符 url[strcspn(url, "\n")] = '\0'; int index = findSuffixIndex(url); if (index != -1) { printf("匹配到后缀%s,索引为%d\n", suffixes[index], index); } else { printf("未匹配到后缀,返回-1\n"); } return 0; }
这个代码能完美处理你提到的两种情况:
- 输入
www.stackoverflow.com,提取com,匹配数组返回0; - 输入
www.google.com.tr,提取com,匹配数组返回0; - 输入
www.example.org,提取org,返回1。
回到你的问题:scanf到底能不能?
如果一定要用scanf,那只能针对固定格式的URL做处理,比如先统计URL里的点数量,再用对应的格式字符串。比如:
#include <stdio.h> #include <string.h> int main() { char url[256]; char suffix[32]; printf("输入URL:"); scanf("%s", url); // 统计点的数量 int dot_count = 0; for (int i = 0; url[i]; i++) { if (url[i] == '.') dot_count++; } if (dot_count == 2) { // 格式:xxx.xxx.xxx,提取最后一个xxx sscanf(url, "%*[^.]%*c%*[^.]%*c%s", suffix); } else if (dot_count == 3) { // 格式:xxx.xxx.xxx.xxx,提取倒数第二个xxx char temp[32]; sscanf(url, "%*[^.]%*c%*[^.]%*c%s%*c%s", suffix, temp); } else { printf("格式不支持\n"); return -1; } // 匹配数组逻辑 const char* suffixes[] = {"com", "org", "net", "edu"}; const int suffix_count = sizeof(suffixes)/sizeof(suffixes[0]); int index = -1; for (int i = 0; i < suffix_count; i++) { if (strcmp(suffix, suffixes[i]) == 0) { index = i; break; } } printf("后缀:%s,索引:%d\n", suffix, index); return index; }
但这个代码的问题很明显:只能处理2个或3个点的URL,要是URL有1个点(比如example.com)或者更多点(比如a.b.c.d.e.com),就直接失效了。而且scanf读取URL时遇到空格会停止,也不符合实际URL的使用场景。
所以总结一下:scanf可以做,但只适合非常固定的简单场景,大部分情况下,用字符串处理函数写自定义函数会更可靠、灵活。
内容的提问来源于stack exchange,提问作者SarpSTA

