/************************************************************************ * AUTHOR: NiuJiuRu * FILENAME: swstring.c * DESCRIPTION: 字符串操作扩展函数 * NOTE: * HISTORY: * 1, [2010-07-05] created by NiuJiuRu * 2, [2014-01-10] 修改"sw_str_getFieldName()"和"sw_str_getFieldValue()" 函数 ***********************************************************************/ #include "swapi.h" #include "swchar.h" #include "swstring.h" /* 将所有字符转化成小写 */ char *xstrtolower(char *str) { int i = 0, len = 0; if(str) len = strlen(str); for(i = 0; i < len; i++) { if(xisupper(str[i])) str[i] = tolower(str[i]); } return str; } /* 将所有字符转化成大写 */ char *xstrtoupper(char *str) { int i = 0, len = 0; if(str) len = strlen(str); for(i = 0; i < len; i++) { if(xislower(str[i])) str[i] = toupper(str[i]); } return str; } /* 在一个字符串内, 统计其包含某个给定字符的个数 */ int xstrcharcnt(const char *str, char c) { int i = 0, len = 0, cnt = 0; if(str) len = strlen(str); else return -1; for(i = 0; i < len; i++) { if(str[i] == c) cnt++; } return cnt; } /* 在一个字符串内, 用一个给定的字符替换一个已存在的字符 */ int xstrcharreplace(char *str, char src, char dst) { int i = 0, len = 0, cnt = 0; if(str) len = strlen(str); else return -1; for(i = 0; i < len; i++) { if(str[i] == src) { str[i] = dst; cnt++; } } return cnt; } /* 是否一个整数字符串 */ bool xstrisint(const char *str) { int i = 0, len = 0; if(str) len = strlen(str); else return false; for(i = 0; i < len; i++) { if(!xisdigit(str[i])) return false; } return true; } /* 是否一个十六进制字符串 */ bool xstrishex(const char *str) { int i = 0, len = 0; if(str) len = strlen(str); else return false; for(i = 0; i < len; i++) { if(!xisxdigit(str[i])) return false; } return true; } /* 是否一个浮点字符串 */ bool xstrisfloat(const char *str) { int i = 0, len = 0; if(str) len = strlen(str); else return false; if(xstrcharcnt(str, '.') != 1) return false; for(i = 0; i < len; i++) { if(!xisdigit(str[i]) && str[i] != '.') return false; } return true; } /* 不区分大小写的比较字符串 */ int xstrcasecmp(const char *s1, const char *s2) { int i = 0, ret = 0; if(!s1 && !s2) return 0; else if(!s1 && s2) return -1; else if(s1 && !s2) return 1; while(s1[i] != 0 && s2[i] != 0) { ret = toupper(s1[i]) - toupper(s2[i]); if(ret != 0) goto EndP; i++; } ret = toupper(s1[i]) - toupper(s2[i]); EndP: if(ret == 0) return 0; else if(ret < 0) return -1; else return 1; } /* 不区分大小写的比较字符串的前n个字符 */ int xstrncasecmp(const char *s1, const char *s2, int n) { int i = 0, ret = 0; if(!s1 && !s2) return 0; else if(!s1 && s2) return -1; else if(s1 && !s2) return 1; while(s1[i] != 0 && s2[i] != 0 && i < n) { ret = toupper(s1[i]) - toupper(s2[i]); if(ret != 0) goto EndP; i++; } if(i < n) ret = toupper(s1[i]) - toupper(s2[i]); EndP: if(ret == 0) return 0; else if(ret < 0) return -1; else return 1; } /* 不区分大小写的在一个字符串中查找子字符串 */ // mode: 1, "left" - 从字符串的开始位置向后查找; 2, "right" - 从字符串的结束位置向前查找 char *xstrcasestr(const char *str, const char *mode, const char *child) { char *p = NULL; int len = 0; if(!str || !mode || !child) return NULL; len = strlen(child); // get the child string's length if(xstrcasecmp(mode, "left") == 0) { p = (char *)str; while(*p != '\0') { if(xstrncasecmp(p, child, len) == 0) return p; p += 1; } } else if(xstrcasecmp(mode, "right") == 0) { p = ((char *)str+strlen(str)-1)-(len-1); while(p >= str) { if(xstrncasecmp(p, child, len) == 0) return p; p -= 1; } } return NULL; } /* 不区分大小写的在一个字符串中查找字符 */ // mode: 1, "left" - 从字符串的开始位置向后查找; 2, "right" - 从字符串的结束位置向前查找 char *xstrcasechr(const char *str, const char *mode, char c) { char buf[2] = { 0 }; sprintf(buf, "%c", c); return xstrcasestr(str, mode, buf); } // 转换时间结构体到字符串 static char *tmtostr(char *str, const struct tm *pTime, short ms, const char *mode) { if(!str || !pTime || ms < 0 || !mode) return NULL; if(xstrcasecmp(mode, "datetime") == 0) { sprintf(str, "%04d-%02d-%02d %02d:%02d:%02d", pTime->tm_year+1900, pTime->tm_mon+1, pTime->tm_mday, pTime->tm_hour, pTime->tm_min, pTime->tm_sec); } else if(xstrcasecmp(mode, "datetime(h)") == 0) { sprintf(str, "%04d-%02d-%02d %02d:%02d:%02d.%03hd", pTime->tm_year+1900, pTime->tm_mon+1, pTime->tm_mday, pTime->tm_hour, pTime->tm_min, pTime->tm_sec, ms); } else if(xstrcasecmp(mode, "date") == 0) { sprintf(str, "%04d-%02d-%02d", pTime->tm_year+1900, pTime->tm_mon+1, pTime->tm_mday); } else if(xstrcasecmp(mode, "time") == 0) { sprintf(str, "%02d:%02d:%02d", pTime->tm_hour, pTime->tm_min, pTime->tm_sec); } else if(xstrcasecmp(mode, "time(h)") == 0) { sprintf(str, "%02d:%02d:%02d.%03hd", pTime->tm_hour, pTime->tm_min, pTime->tm_sec, ms); } else return NULL; return str; } // 转换字符串到时间结构体 static struct tm *strtotm(const char *str, struct tm *pTime, short *ms, const char *mode) { time_t now = { 0 }; struct tm *pNow = NULL; if(!str || !pTime || !ms || !mode) return NULL; time(&now); pNow = localtime(&now); // get current time if(xstrcasecmp(mode, "datetime") == 0) { sscanf(str, "%04d-%02d-%02d %02d:%02d:%02d", &pTime->tm_year, &pTime->tm_mon, &pTime->tm_mday, &pTime->tm_hour, &pTime->tm_min, &pTime->tm_sec); pTime->tm_year -= 1900; pTime->tm_mon -= 1; } else if(xstrcasecmp(mode, "datetime(h)") == 0) { sscanf(str, "%04d-%02d-%02d %02d:%02d:%02d.%03hd", &pTime->tm_year, &pTime->tm_mon, &pTime->tm_mday, &pTime->tm_hour, &pTime->tm_min, &pTime->tm_sec, ms); pTime->tm_year -= 1900; pTime->tm_mon -= 1; } else if(xstrcasecmp(mode, "date") == 0) { sscanf(str, "%04d-%02d-%02d", &pTime->tm_year, &pTime->tm_mon, &pTime->tm_mday); pTime->tm_year -= 1900; pTime->tm_mon -= 1; } else if(xstrcasecmp(mode, "time") == 0) { pTime->tm_year = pNow->tm_year; pTime->tm_mon = pNow->tm_mon; pTime->tm_mday = pNow->tm_mday; sscanf(str, "%02d:%02d:%02d", &pTime->tm_hour, &pTime->tm_min, &pTime->tm_sec); } else if(xstrcasecmp(mode, "time(h)") == 0) { pTime->tm_year = pNow->tm_year; pTime->tm_mon = pNow->tm_mon; pTime->tm_mday = pNow->tm_mday; sscanf(str, "%02d:%02d:%02d.%03hd", &pTime->tm_hour, &pTime->tm_min, &pTime->tm_sec, ms); } else return NULL; return pTime; } /* 获取系统当前的日期时间到字符串 */ // mode: 1, "datetime" - 日期和时间; 2, "datetime(h)" - 日期和时间(精确到毫秒); 3, "date" - 只有日期; // 4, "time" - 只有时间; 5, "time(h)" - 只有时间(精确到毫秒) char *xstrgettime(char *str, const char *mode) { /* 过时代码 2025-07-21废弃 struct timeb timeBuf = { 0 }; ftime(&timeBuf); return tmtostr(str, localtime(&timeBuf.time), timeBuf.millitm, mode);*/ struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); return tmtostr(str, localtime(&ts.tv_sec), ts.tv_nsec / 1000000, mode); } /* 改变一个日期时间字符串(单位: 毫秒)的值 */ // mode: 1, "datetime" - 日期和时间; 2, "datetime(h)" - 日期和时间(精确到毫秒); 3, "date" - 只有日期; // 4, "time" - 只有时间; 5, "time(h)" - 只有时间(精确到毫秒) char *xstrtimegrow(char *str, const char *mode, int64_t ms) { struct tm oldTime = { 0 }; time_t newTime = 0; short millisecond = 0; if(!strtotm(str, &oldTime, &millisecond, mode)) return NULL; newTime = mktime(&oldTime); if(newTime < 0) return NULL; newTime += (time_t)((millisecond+ms)/1000); millisecond = (short)((millisecond+ms)%1000); if(millisecond < 0) { newTime -= 1; millisecond = millisecond + 1*1000; } return tmtostr(str, localtime(&newTime), millisecond, mode); } /* 比较两个日期时间字符串, 并得到它们之间的差值(单位: 毫秒) */ // mode: 1, "datetime" - 日期和时间; 2, "datetime(h)" - 日期和时间(精确到毫秒); 3, "date" - 只有日期; // 4, "time" - 只有时间; 5, "time(h)" - 只有时间(精确到毫秒) bool xstrtimecmp(const char *s1, const char *s2, const char *mode, int64_t *interval) { struct tm tm1 = { 0 }, tm2 = { 0 }; time_t time1 = 0, time2 = 0; short millisecond1 = 0, millisecond2 = 0; if(s1) { if(!strtotm(s1, &tm1, &millisecond1, mode)) return false; time1 = mktime(&tm1); if(time1 < 0) return false; } if(s2) { if(!strtotm(s2, &tm2, &millisecond2, mode)) return false; time2 = mktime(&tm2); if(time2 < 0) return false; } if(interval) *interval = (int64_t)(time1-time2)*1000+(millisecond1-millisecond2); return true; } /* 使用Unix时间戳字符串设置系统时间 */ int xsetlocaltime(const char *timestamp) { char *end; if(!timestamp) return -1; errno = 0; long long t = strtoll(timestamp, &end, 10); if(errno || *end) return -1; #if LONG_MAX < 0x7FFFFFFFFFFFFFFFLL if(t > LONG_MAX) return -1; #endif struct timeval tv = { .tv_sec = (time_t)t, .tv_usec = 0 }; return settimeofday(&tv, NULL); } // Retrieves the number of milliseconds that have elapsed since the system was started int xgettickcount(unsigned long *tick) { if(!tick) return -1; struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); *tick = (ts.tv_sec*1000 + ts.tv_nsec/1000000); return 0; } /* 不区分大小写的将一个十六进制字符串转换为它所对应的十六进制数据 */ // 1, 可自动处理"0x"/"0X"前缀、空格、逗号、'\t'、'\r'、'\n'等控制字符 int xstrtohex(const char *str, unsigned char *hex) { char *p = NULL, hexStr[3] = { 0 }; short hexNum = 0, cnt = 0; if(!str || !hex) return -1; p = (char *)str; while(*p != '\0') { if(*p == '0' && (*(p+1) == 'x' || *(p+1) == 'X')) { p += 2; continue; } if(!xisxdigit(*p)) { p++; continue; } memset(hexStr, 0, sizeof(hexStr)); if(xisxdigit(*(p+1))) { memcpy(hexStr, p, 2); p += 2; } else { memcpy(hexStr, p, 1); p += 1; } sscanf(hexStr, "%hx", &hexNum); *(hex+cnt) = (unsigned char)hexNum; cnt++; } return cnt; } /* 从一个十六进制数据缓冲中构建出一个它所对应的十六进制字符串 */ // 1, 可自动添加"0x"/"0X"前缀、空格、逗号等分割符 int xstrfromhex(const unsigned char *hex, int hexCnt, char *str, const char *prefix, const char *split) { char hexStr[6] = { 0 }; int i = 0; if(!hex || hexCnt <= 0 || !str || (prefix && strlen(prefix) > 2)) return -1; for(i = 0; i < hexCnt; i++) { memset(hexStr, 0, sizeof(hexStr)); if(prefix) strcat(hexStr, prefix); sprintf(hexStr+strlen(hexStr), "%02x", hex[i]); if(split && i < hexCnt-1) strcat(hexStr, split); strcat(str, hexStr); } return i; } // 在一个特定数据格式的Buffer中查找"数据段" static bool FindDataArea(const char *buf, int bufSize, char delimiter, const char *name, const char *value, char **start, char **equal, char **end) { char *s = NULL, *o = NULL, *e = NULL, *p = NULL; if(!buf || bufSize <= 0 || (!name && !value)) return false; if(delimiter == 0) delimiter = '\n'; else if(!xispunct(delimiter) && delimiter != '\n') return false; else if(delimiter == '=') return false; if((name && strchr(name, delimiter)) || (value && strchr(value, delimiter))) return false; if((name && strchr(name, '=')) || (value && strchr(value, '='))) return false; p = (char *)buf; while(p <= buf+bufSize-1) { // 1, 记录一个"数据段"的开始位置 s = p; // 2, 找到该"数据段"的结束位置 while(*p != delimiter && p+1 <= buf+bufSize-1) p++; e = p; p = s; // 3, 判断该"数据段"是否为注释段 while((xiscntrl(*p) || xisspace(*p)) && p < e) p++; if(p[0] == '#' || (p[0] == '/' && p[1] == '/')) goto NextSegment; // 4, 根据"字段名"过滤 if(name) { if(xstrncasecmp(p, name, strlen(name)) != 0) goto NextSegment; if(p+strlen(name) <= e) p += strlen(name); else goto NextSegment; while((xiscntrl(*p) || xisspace(*p)) && p < e) p++; } else while(*p != '=' && p < e) p++; // 5, 记录'='号的位置 if(*p == '=') { o = p; if(p < e) p += 1; } else goto NextSegment; // 6, 根据"字段值"过滤 if(value) { while((xiscntrl(*p) || xisspace(*p)) && p < e) p++; if(xstrncasecmp(p, value, strlen(value)) != 0) goto NextSegment; if(p+strlen(value) <= e) { p += strlen(value); while((xiscntrl(*p) || xisspace(*p)) && p < e) p++; if(p != e) goto NextSegment; if(!(*e == delimiter || *e == '=' || (xiscntrl(*e) || xisspace(*e)))) goto NextSegment; } else if(!(p+strlen(value)-1 == e)) goto NextSegment; } // 7, 找到了一个符合条件的"数据段", 返回结果 if(start) *start = s; if(equal) *equal = o; if(end) { if(*e == delimiter) *end = e; else if(e == buf+bufSize-1) { while(*e == 0x00 && e > o) e--; *end = e; } else ; // 根据上文逻辑, 不可能出现此种情形 } return true; // 8, 继续比对下一"数据段" NextSegment: p = e + 1; } return false; } // 在一个特定数据格式的Buffer中更新"数据段" static bool UpdateDataArea(char *buf, int bufSize, char delimiter, const char *name, const char *value, bool autoAdd, int updateType, int *varySize) { char *s = NULL, *e = NULL, *z = NULL; int areaSize = 0, freeSize = 0, incSize = 0, delimiterLen = 0; bool findOk = false; if(!buf || bufSize <= 0 || !name || !value) return false; if(delimiter == 0) delimiter = '\n'; else if(!xispunct(delimiter) && delimiter != '\n') return false; else if(delimiter == '=') return false; if(strchr(name, delimiter) || strchr(value, delimiter)) return false; if(strchr(name, '=') || strchr(value, '=')) return false; // 计算待更新的目标"数据段"的大小 areaSize = strlen(name) + strlen("=") + strlen(value); // 计算Buffer尾尚未使用的空闲空间 z = buf + bufSize - 1; while(*z == 0x00 && z > buf) { freeSize++; z--; } // 查找符合更新条件"数据段" if(updateType == 0) findOk = FindDataArea(buf, bufSize, delimiter, name, NULL, &s, NULL, &e); // 按"字段名"查找 else if(updateType == 1) findOk = FindDataArea(buf, bufSize, delimiter, NULL, value, &s, NULL, &e); // 按"字段值"查找 else return false; // 找到了目标"数据段" if(findOk) { // 调整目标"数据段"的尾指针 if(*e == delimiter) { e -= 1; if(delimiter == '\n' && *e == '\r') e -= 1; } // 计算目标"数据段"为了此次更新操作而产生的空间大小变化 incSize = areaSize-(e-s+1); if(incSize > freeSize) return false; // 处理目标"数据段"的所有后续"数据段" if(e < z && incSize != 0) memmove((e+1)+incSize, e+1, z-e); if(incSize < 0) memset((z+1)+incSize, 0, -incSize); // 更新目标"数据段" memcpy(s, name, strlen(name)); memcpy(s+strlen(name), "=", strlen("=")); memcpy(s+strlen(name)+strlen("="), value, strlen(value)); if(varySize) *varySize = incSize; return true; } // 添加一个新的"数据段" if(autoAdd && freeSize > 1) { // 初始化"定界符"长度 delimiterLen = 0; // 判断是否需要在新添加的"数据段"前加入"定界符" if(*z == delimiter) z += 1; else if(z != buf) { z += 1; if(delimiter == '\n') { if(*z != '\r') { if(*z == 0x00) delimiterLen++; *z = '\r'; } z += 1; } if(*z != delimiter) { if(*z == 0x00) delimiterLen++; *z = delimiter; } z += 1; } // 判断Buffer中是否还有足够的空闲空间用于此次添加操作 if(areaSize+delimiterLen > freeSize) { if(delimiterLen > 0) { z -= delimiterLen; memset(z, 0, delimiterLen); } return false; } // 设置新添加的"数据段" memcpy(z, name, strlen(name)); memcpy(z+strlen(name), "=", strlen("=")); memcpy(z+strlen(name)+strlen("="), value, strlen(value)); if(varySize) *varySize = areaSize+delimiterLen; return true; } return false; } // 在一个特定数据格式的Buffer中删除"数据段" static bool DeleteDataArea(char *buf, int bufSize, char delimiter, const char *name, const char *value, int *varySize) { char *s = NULL, *e = NULL, *z = NULL; if(!buf || bufSize <= 0 || (!name && !value)) return false; if(delimiter == 0) delimiter = '\n'; else if(!xispunct(delimiter) && delimiter != '\n') return false; else if(delimiter == '=') return false; if((name && strchr(name, delimiter)) || (value && strchr(value, delimiter))) return false; if((name && strchr(name, '=')) || (value && strchr(value, '='))) return false; // 查找目标"数据段" if(!FindDataArea(buf, bufSize, delimiter, name, value, &s, NULL, &e)) return true; // 得到Buffer中最后一个"数据段"的结束位置 z = buf + bufSize - 1; while(*z == 0x00 && z > buf) z--; // 删除目标"数据段" if(e < z) memmove(s, e+1, z-e); memset(s+(z-e), 0, z-(s+(z-e))+1); if(varySize) *varySize = -(z-(s+(z-e))+1); return true; } /* 不区分大小写的在特定数据格式的Buffer中根据"字段值"设置它所对应的"字段名" */ // 1, Buffer中数据的组成格式为: "n1 = v1"+"定界符"+"n2 = v2"+"定界符"+..."nn = vn"("="号的左边为"字段名", // 右边为"字段值") // 2, 可自动识别处理空格、'\t'、'\r'、'\n'等控制字符 bool sw_str_setFieldName(char *buf, int bufSize, char delimiter, const char *name, const char *value, bool autoAdd, int *varySize) { return UpdateDataArea(buf, bufSize, delimiter, name, value, autoAdd, 1, varySize); } /* 不区分大小写的在特定数据格式的Buffer中根据"字段值"取得它所对应的"字段名" */ // 1, Buffer中数据的组成格式为: "n1 = v1"+"定界符"+"n2 = v2"+"定界符"+..."nn = vn"("="号的左边为"字段名", // 右边为"字段值") // 2, 可自动识别处理空格、'\t'、'\r'、'\n'等控制字符 char *sw_str_getFieldName(const char *buf, int bufSize, char delimiter, char *name, int nameSize, const char *value) { char *s = NULL, *o = NULL; int nameLen; if(!FindDataArea(buf, bufSize, delimiter, NULL, value, &s, &o, NULL)) return NULL; if(o > s) o--; else { name[0] = '\0'; goto EndP; } while((xiscntrl(*s) || xisspace(*s)) && s < o) s++; while((xiscntrl(*o) || xisspace(*o)) && o > s) o--; if(o == s && (xiscntrl(*o) || xisspace(*o))) nameLen = 0; else nameLen = (o-s+1); if(nameLen < nameSize) { memcpy(name, s, nameLen); name[nameLen] = '\0'; } else return NULL; EndP: return name; } /* 不区分大小写的在特定数据格式的Buffer中根据"字段名"删除该"字段" */ // 1, Buffer中数据的组成格式为: "n1 = v1"+"定界符"+"n2 = v2"+"定界符"+..."nn = vn"("="号的左边为"字段名", // 右边为"字段值") // 2, 可自动识别处理空格、'\t'、'\r'、'\n'等控制字符 bool sw_str_delFieldByName(char *buf, int bufSize, char delimiter, const char *name, int *varySize) { return DeleteDataArea(buf, bufSize, delimiter, name, NULL, varySize); } /* 不区分大小写的在特定数据格式的Buffer中根据"字段名"设置它所对应的"字段值" */ // 1, Buffer中数据的组成格式为: "n1 = v1"+"定界符"+"n2 = v2"+"定界符"+..."nn = vn"("="号的左边为"字段名", // 右边为"字段值") // 2, 可自动识别处理空格、'\t'、'\r'、'\n'等控制字符 bool sw_str_setFieldValue(char *buf, int bufSize, char delimiter, const char *name, const char *value, bool autoAdd, int *varySize) { return UpdateDataArea(buf, bufSize, delimiter, name, value, autoAdd, 0, varySize); } /* 不区分大小写的在特定数据格式的Buffer中根据"字段名"取得它所对应的"字段值" */ // 1, Buffer中数据的组成格式为: "n1 = v1"+"定界符"+"n2 = v2"+"定界符"+..."nn = vn"("="号的左边为"字段名", // 右边为"字段值") // 2, 可自动识别处理空格、'\t'、'\r'、'\n'等控制字符 char *sw_str_getFieldValue(const char *buf, int bufSize, char delimiter, const char *name, char *value, int valueSize) { char *o = NULL, *e = NULL; int valueLen; if(!FindDataArea(buf, bufSize, delimiter, name, NULL, NULL, &o, &e)) return NULL; if(o < e) o++; else { value[0] = '\0'; goto EndP; } while((xiscntrl(*o) || xisspace(*o)) && o < e) o++; while((xiscntrl(*e) || xisspace(*e)) && e > o) e--; if(o == e && (xiscntrl(*o) || xisspace(*o))) valueLen = 0; else valueLen = (e-o+1); if(valueLen < valueSize) { memcpy(value, o, valueLen); value[valueLen] = '\0'; } else return NULL; EndP: return value; } /* 不区分大小写的在特定数据格式的Buffer中根据"字段值"删除该"字段" */ // 1, Buffer中数据的组成格式为: "n1 = v1"+"定界符"+"n2 = v2"+"定界符"+..."nn = vn"("="号的左边为"字段名", // 右边为"字段值") // 2, 可自动识别处理空格、'\t'、'\r'、'\n'等控制字符 bool sw_str_delFieldByValue(char *buf, int bufSize, char delimiter, const char *value, int *varySize) { return DeleteDataArea(buf, bufSize, delimiter, NULL, value, varySize); }