[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[FDclone-users:01025] Re: Re: [FDclone-users:01021] Re: ファイルのソート結果が不定となる場合



 しらいです。

 追試を行なったので補足。

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 ----

                                               しらい たかし