作者gn00618777 (非常念旧)
看板C_and_CPP
标题Re: [问题] 版本字串比较
时间Fri Oct 2 22:55:31 2020
※ 引述《gn00618777 (非常念旧)》之铭言:
: release 版本格式: x.x.xxx
: 目的 : 1.1.066 以及 1.1.66 ,程式都能认定同一版本。
: (为了防止开发者少填1个0,也就是1.1.66)
: (少填1个0,会使strncmp 1.1.66 > 1.1.066)
: (我是觉得公司都已经规定格式了,1.1.66不就不被允许吗..)
: (但上层总是想得比我们下面的人多拉~)
: (所以我用了每小数点为分隔来求出每个数字来比)
: (因此就能认定1.1.066 == 1.1.66了)
: version 会存在既定 array(a_version, b_version)因为到时写成 fun传入来源指标
: 用strtok系列会改变来源位址,所以用a_version, b_version既定来存
: char a_version[] = "1.1.066";
: char b_version[] = "1.1.66";
: char *a_ptr = NULL;
: char *b_ptr = NULL;
: char *p,*q;
: int i = 0;
: int result = 0;
: p = strtok_r(a_version, ".", &a_ptr);
: q = strtok_r(b_version, ".", &b_ptr);
: while(p != NULL && q != NULL) {
: if((int)strtoul(p, NULL, 10) > (int)strtoul(q, NULL, 10)) {
: result = 1;
: break;
: } else if((int)strtoul(p, NULL, 10) < (int)strtoul(q, NULL, 10)) {
: result = -1;
: break;
: } else {
: //do nothing
: }
: p = strtok_r(NULL, ".", &a_ptr);
: q = strtok_r(NULL, ".", &b_ptr);
: }
: return result; //1: a>b -1:a<b 0: a==b
要用一个 buffer 的写法我放弃了,我觉得应该还是要用两个空间去存比较安全
原因 1 strtok 会改到source
原因 2 确保source 进来结尾能是'\0'
有些大大热心提供的程式我还未消化完,非常感谢。我先提供自己的完整写法
有些环境编译器没有 strtok_r的header,我是使用
https://reurl.cc/bRVono
glibc porting过来的。
并搭配 leetcode 165 的测试题
https://reurl.cc/GrjYVG 验证。另外我比leetcode
要求的回传1 or -1 or 0 更进一步,我的不只回传1 -1 0 ,可以回传大多少小多少
有觉得更好的建议再多多指教罗。
int compare_version(const char *str1_version, const char *str2_version) {
char a_version[FW_VERSION_SIZE+1] = {0};
char b_version[FW_VERSION_SIZE+1] = {0};
char *a_ptr = NULL, *b_ptr = NULL;
char *p = NULL, *q = NULL;
int a = 0, b = 0;
if(str1_version)
strncpy(a_version, str1_version, FW_VERSION_SIZE);
if(str2_version)
strncpy(b_version, str2_version, FW_VERSION_SIZE);
p = strtok_r(a_version, ".", &a_ptr);
q = strtok_r(b_version, ".", &b_ptr);
if(p) a = atoi(p);
if(q) b = atoi(q);
if(a != b) return a - b;
while(a == b) {
p = strtok_r(NULL, ".", &a_ptr);
q = strtok_r(NULL, ".", &b_ptr);
p != NULL ? (a = atoi(p)) : (a = 0);
q != NULL ? (b = atoi(q)) : (b = 0);
if(p == NULL && q == NULL)
return 0;
}
return a - b;
}
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 59.115.84.195 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1601650535.A.301.html
※ 编辑: gn00618777 (59.115.84.195 台湾), 10/02/2020 23:01:41
1F:→ loveme00835: 你的问题在於还没分析完全就开始实作, C 语言有两种 10/03 09:27
2F:→ loveme00835: 字串, 一种是 C-style string, 另一种不是用内容来分 10/03 09:27
3F:→ loveme00835: 而是用 (char*,size_t) 这样的 tuple描述, 前者无法 10/03 09:28
4F:→ loveme00835: 支援巢状结构, 所以 strtok() 是用截断的方式, 但我 10/03 09:29
5F:→ loveme00835: 们如果要想拿出子字串, 应该使用後者, 这样既不用改 10/03 09:29
6F:→ loveme00835: 变输入字串内容, 也可以更有系统的描述问题, 在你的 10/03 09:30
7F:→ loveme00835: 问题里, 目标即是将输入的字串拆成 3 个 tuple, 分别 10/03 09:31
8F:→ loveme00835: 为: (a_version, 1), (a_version + 2, 1), (a_versio 10/03 09:33
9F:→ loveme00835: n + 4, 3) 只要给你任何字串都有办法拆出 n 个 tuple 10/03 09:34
10F:→ loveme00835: 那版本字串的比对问题就转变为 n 的 tuple 各自去比 10/03 09:34
11F:→ loveme00835: 较的问题了, 比较 tuple 甚至也不一定要先转成整数, 10/03 09:35
12F:→ loveme00835: 类似像 strncmp() 的逻辑甚至是反方向地比对字元也是 10/03 09:36
13F:→ loveme00835: 原文推文已经提供可以客制化的实作了, 核心概念就是 10/03 09:39
14F:→ loveme00835: 两个 while 回圈去萃取 tuple 而已, 剩下就看你理解 10/03 09:39
15F:→ loveme00835: 程度 10/03 09:39
16F:推 annheilong: 想知道C语言第二种字串的型别是...? 10/05 10:07
17F:推 LPH66: std::string 内部即是这种结构, 只除了 char* 也是他管而已 10/05 10:19
18F:→ LPH66: 这种表示法的好处是字串长度是 O(1) 操作, 不像 strlen 是 10/05 10:20
19F:→ LPH66: O(n) 操作; 另外就是如果 char* 不是自己管的 (例子像是 10/05 10:20
20F:→ LPH66: std::string_view) 那就能如上面推文进行更有弹性的操作 10/05 10:20
21F:→ LPH66: 以上是 C++ 的东西, 但 C 也不是不能自己自订一个结构来用 10/05 10:21
22F:→ LPH66: 那因为这种做法是因为一种 Pascal 的实作所推广的 10/05 10:22
23F:→ LPH66: 因此一般会称这种做法的字串叫 pascal string 10/05 10:22
24F:→ loveme00835: 另一种字串即是在标准函式库里抽象化存在, 但语言上 10/05 11:13
25F:→ loveme00835: 没有明确定义的, 如 strncmp()/strncpy() 等, 从介面 10/05 11:16
26F:→ loveme00835: 上会衍伸一个问题: 如果 C-style 字串只复制前面 n 10/05 11:17
27F:→ loveme00835: 个字元, 不包含 '\0', 那复制而来的算不算字串? 虽然 10/05 11:18
28F:→ loveme00835: 它和 C-style 字串不同, 但却已经是字串处理很基本的 10/05 11:20
29F:→ loveme00835: 元件 10/05 11:21