[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[FDclone-users:01025] Re: Re: [FDclone-users:01021] Re: ファイルのソート結果が不定となる場合
- Subject: [FDclone-users:01025] Re: Re: [FDclone-users:01021] Re: ファイルのソート結果が不定となる場合
- From: Takashi SHIRAI <shirai@unixusers.net>
- Date: Fri, 24 May 2013 18:15:49 +0900
しらいです。
追試を行なったので補足。
In Message-Id <20130523200137.5B2734806A3@yuka.unixusers.net>
Takashi SHIRAI <shirai@unixusers.net>writes:
> しらいです。
> 小松さんのコードだと文字列として長い方が大きな数値というこ
> とになるので、例えばこんな不自然な並び方になりました。
> test1.99.c
> test1.999.c
> test1.0001.c
> test1.0009.c
> test1.2000.c
> test1.11111.c
> strverscmp(3) によると、0 から始まる数字列はその前にある小
> 数点が省略されていると見なすそうなので、実装コードは結構複雑
> になりそうですね。
その strverscmp() ですが、こちらも実際に試してみると何とも
不自然な並びになりますね。ソース読もうとしたんですがテーブル
多用してて読みにくいんで断念しました。
test2.000.c
test2.001.c
test2.0013.c
test2.009.c
test2.00.c
test2.00a.c
test3.01.c
test3.010.c
test3.011.c
test3.019.c
test3.0113.c
test3.01a.c
test4.21.c
test4.21a.c
test4.210.c
test4.211.c
test4.219.c
test4.2113.c
少なくとも man page にある「0 で始まると小数点云々」の下り
は実装と異なっていますね。3.019 と 3.0113 の大小は小学生にも
理解出来る常識問題です。
関数名から version 文字列の比較を意図しているんだと思われ
ますが、数値用に設計された訳ではないとしてもこの仕様は使いに
くそうですね。
むしろ version 文字列なんて作者によって規則がまちまちなの
で、小数点云々と言わずにもっと単純な比較規則にした方が納得し
て貰えるような気がします。
それでも、例えば「1.2」と「1.20」のどちらが若い version な
のかなんて問題は、解釈が分かれるところだと思いますので、絶対
的な規則は作れそうにありませんけどね。
完璧ではないものの多くの支持を得られそうな仕様にするとした
らこんな感じの規則になるんじゃないでしょうか。
A.文字の大小関係は「英字」>「数字」>「それ以外」と見なす。
→「1_234_56」みたいな version 表記もたまに見ます。
B.「それ以外」で区切られた部分文字列をブロックと見なす。
→version 文字列の major/minor 区切り子は英数以外でしょう。
C.二回目以降に現れた数値ブロックは小数点以下と見なす。
→0 で始まっているか否かで規則が異なるのは不自然です。
D.初回の数値ブロックは長さ優先の比較にする。
→「0.1」より「00.1」の方が大きくて構わないでしょう。
E.小数点以下ブロックは文字優先の比較にする。
→A.のルールがあるので数学的に自然な並びになる筈です。
F.英字が現れたらブロック番号をリセットする。
→「1.00rc5」みたいな version 表記も良く見ます。
実装例はこちら。
---- Cut Here ----
#define K_EXTERN
#include "headers.h"
#include "kctype.h"
#define VT_OTHER 1
#define VT_DIGIT 2
#define VT_ALPHA 3
static int NEAR verstype __P_((int));
int strverscmp2 __P_((CONST char *, CONST char *, int));
static int NEAR verstype(c)
int c;
{
if (Xisdigit(c)) return(VT_DIGIT);
if (Xisalpha(c)) return(VT_ALPHA);
return(VT_OTHER);
}
int strverscmp2(s1, s2, nocase)
CONST char *s1, *s2;
int nocase;
{
int n, c1, c2, t1, t2, blk, last;
blk = last = 0;
for (;;) {
c1 = *s1;
c2 = *s2;
n = c1 - c2;
if (!c1 || !c2) return(n);
t1 = verstype(c1);
switch (t1) {
case VT_OTHER:
blk++;
break;
case VT_ALPHA:
blk = 0;
break;
default:
break;
}
if (nocase) n = Xtoupper(c1) - Xtoupper(c2);
if (n) break;
if (iswchar(s1, 0)) {
s1++;
s2++;
if (*s1 != *s2) return((u_char)*s1 - (u_char)*s2);
}
last = t1;
s1++;
s2++;
}
t2 = verstype(c2);
if (blk > 0) /*EMPTY*/;
else if (last == VT_DIGIT || (t1 == VT_DIGIT && t2 == VT_DIGIT)) {
for (;;) {
if (t1 != t2) return((t1 == VT_DIGIT) ? 1 : -1);
if (t1 != VT_DIGIT) return(n);
t1 = verstype(*(++s1));
t2 = verstype(*(++s2));
}
}
if (t1 != t2) return(t1 - t2);
return(n);
}
---- Cut Here ----
しらい たかし