#include <stdio.h> // 标准输入输出库
#include <string.h> // 字符串操作库
#include <ctype.h> // 字符处理库(如tolower, isdigit等)
#include <stdbool.h> // 布尔类型支持
#include <stdlib.h> // 内存分配和释放函数
#include "uthash.h" // 轻量级哈希表库
#define MAX_MAC_LENGTH 17 // MAC地址的标准长度(12个十六进制字符+5个分隔符)
#define MAX_INPUT_LENGTH 1000 // 输入字符串的最大长度限制
// 定义哈希表结构体
typedef struct {
char mac[MAX_MAC_LENGTH + 1]; // 存储MAC地址的字符串(+1用于存放字符串结束符'\0')
UT_hash_handle hh; // uthash库所需的哈希表处理句柄
} MacEntry;
MacEntry *mac_table = NULL; // 全局哈希表指针,初始化为NULL
/**
* @brief 检查字符是否为合法的十六进制字符
* @param c 待检查的字符
* @return true 如果是合法的十六进制字符(0-9, a-f, A-F)
* @return false 如果不是合法的十六进制字符
*/
bool is_hex_char(char c) {
return isdigit(c) || (tolower(c) >= 'a' && tolower(c) <= 'f');
}
/**
* @brief 检查子串是否为合法的MAC地址
* @param substr 待检查的子串(长度必须为17)
* @return true 如果是合法的MAC地址
* @return false 如果不是合法的MAC地址
*/
bool is_valid_mac(const char *substr) {
// 检查分隔符是否合法(只能是'-'或':')
char separator = substr[2];
if (separator != '-' && separator != ':') {
return false;
}
// 检查所有分隔符是否一致且位置正确(第2、5、8、11、14位)
for (int i = 2; i <= 14; i += 3) {
if (substr[i] != separator) {
return false;
}
}
// 检查非分隔符的字符是否都是合法的十六进制字符
for (int i = 0; i < MAX_MAC_LENGTH; i++) {
// 跳过分隔符的位置
if (i == 2 || i == 5 || i == 8 || i == 11 || i == 14) {
continue;
}
if (!is_hex_char(substr[i])) {
return false;
}
}
return true;
}
/**
* @brief 标准化MAC地址(统一为小写字母和统一的分隔符)
* @param mac 待标准化的MAC地址(长度必须为17)
* @param separator 统一使用的分隔符('-'或':')
*/
void normalize_mac(char *mac, char separator) {
for (int i = 0; i < MAX_MAC_LENGTH; i++) {
if (i == 2 || i == 5 || i == 8 || i == 11 || i == 14) {
mac[i] = separator; // 统一分隔符
} else {
mac[i] = tolower(mac[i]); // 转换为小写字母
}
}
}
/**
* @brief 统计输入字符串中唯一合法的MAC地址数量
* @param inputStr 输入的字符串
* @return int 唯一合法的MAC地址数量
*/
int count_unique_mac_addresses(const char *inputStr) {
int len = strlen(inputStr);
// 如果输入字符串长度小于MAC地址的标准长度,直接返回0
if (len < MAX_MAC_LENGTH) {
return 0;
}
// 滑动窗口遍历所有可能的17字符子串
for (int i = 0; i <= len - MAX_MAC_LENGTH; i++) {
char substr[MAX_MAC_LENGTH + 1]; // 临时存储子串
strncpy_s(substr, &inputStr[i], MAX_MAC_LENGTH); // 复制子串
substr[MAX_MAC_LENGTH] = '\0'; // 添加字符串结束符
// 检查子串是否为合法的MAC地址
if (is_valid_mac(substr)) {
char separator = substr[2]; // 获取分隔符
normalize_mac(substr, separator); // 标准化MAC地址
// 检查哈希表中是否已存在该MAC地址
MacEntry *entry = NULL;
HASH_FIND_STR(mac_table, substr, entry);
// 如果不存在,则添加到哈希表
if (entry == NULL) {
entry = (MacEntry *)malloc(sizeof(MacEntry));
strcpy(entry->mac, substr);
HASH_ADD_STR(mac_table, mac, entry);
}
}
}
// 获取哈希表中唯一MAC地址的数量
int count = HASH_COUNT(mac_table);
// 清空哈希表,释放内存
HASH_CLEAR(hh, mac_table);
return count;
}
/**
* @brief 测试函数
*/
int main() {
// 测试用例1:合法的MAC地址(使用'-'分隔符)
const char *test1 = "00-11-aa-BB-FF-Ed";
// 测试用例2:合法的MAC地址(使用':'分隔符,应与测试用例1视为相同)
const char *test2 = "00:11:aa:BB:FF:Ed";
// 测试用例3:不合法的MAC地址(混用分隔符)
const char *test3 = "00-11-aa-BB:FF-Ed";
// 测试用例4:两个合法的MAC地址
const char *test4 = "00-11-aa-BB-FF-Ed 00-11-aa-BB-FF-Ee";
// 测试用例5:输入字符串太短
const char *test5 = "short";
// 执行测试并打印结果
printf("测试1: %d\n", count_unique_mac_addresses(test1)); // 预期输出:1
printf("测试2: %d\n", count_unique_mac_addresses(test2)); // 预期输出:1
printf("测试3: %d\n", count_unique_mac_addresses(test3)); // 预期输出:0
printf("测试4: %d\n", count_unique_mac_addresses(test4)); // 预期输出:2
printf("测试5: %d\n", count_unique_mac_addresses(test5)); // 预期输出:0
return 0;
}