From: gotoken@... (GOTO Kentaro) Date: 2000-02-03T00:44:46+09:00 Subject: [ruby-dev:9061] Re: [REQ] Integer#{hex,dec,oct,bin}, String#bin ごとけんです In message "[ruby-dev:9045] Re: [REQ] Integer#{hex,dec,oct,bin}, String#bin" on 00/01/31, GOTO Kentaro writes: >第1引数は、format引数の % と 指定文字のあいだの文字がいいん >ではないかと思います。これは余分なモノを付け加えられなくする >ためです。 >16進に関してはhexとheXのように大文字と小文字のメソッドを分け >たほうがよいと思うです。なまえは大文字の名前は Hex, HEX 等も >考えられますが、heXが分かりやすいような気がしてます。 >それと、負の数に対するフォーマットはRubyのformat流ではなく、 >普通に符号をつけてもらったほうがよいように思います。 >第2引数に句切り幅、第3引数に句切り文字を与えられるとなお良い >あと、binとdecも組み込みにしてもらえるとうれしいですがどうで >しょう?? 以上のものを実装してみました。お試し下さい。 = クラス Bignum, Fixnum == メソッド : bin(fmt, sw, sc), oct(...), dec(...), heX(...), hex(...) 2進、8進、10進、16進(大文字、小文字)表示の文字列を返す。 第1引数 fmt はフォーマット文字列で、高々1個の`+'で始まり、そ の後には0個以上の数字のみを続けることが出来る。最初に現れる `0'以外の数字以降は最小のフォーマット幅をあらわし、その幅の 中でselfのn進表示が右詰めされる。最初の数字が`0'のときは最小 幅に満たない部分は`0'で埋められる。最初の文字が`+'ならば必ず 符号が付けられ、さらに最初の数字が`0'ならば最小幅はその分1つ 長くなる。 第2引数 sw は区切り幅、第3引数 sc は区切り文字。sw>0のとき下 位桁からsw文字ごとにscで区切る。またsw>0のとき最小フォーマッ ト幅は W+(W-1)/sep となる。ここで W はsw<=0のときの最小幅。 scは文字コードでなく文字列で与えてもよいが1バイト文字に限り2 バイト目以降は無視される。 なお、fmt, sw, sc のデフォルト値はそれぞれ "", 0, ?_ である。 -- gotoken # 以下、死んでる最中の現実逃避の成果 Tue Feb 02 14:32:20 2000 GOTO Kentaro * bignum.c: implemented methods bin,oct,dec,hex and heX. * numeric.c: ditto. Index: bignum.c =================================================================== RCS file: /home/cvs/ruby/bignum.c,v retrieving revision 1.5 diff -u -r1.5 bignum.c --- bignum.c 2000/01/05 04:36:56 1.5 +++ bignum.c 2000/02/02 14:31:10 @@ -1335,6 +1335,147 @@ return Qfalse; } +static VALUE +big_represent(bchar, num, argc, argv) + char bchar; + VALUE num; + int argc; + VALUE *argv; +{ + unsigned int width = 0; + unsigned char sep = '_'; + int addsign = 0; + int i, j, k, len, mod; + char *ptr, *res, *tmp, *rp; + VALUE buf, *args; + + switch (argc) { + case 3: + if (!FIXNUM_P(argv[2])) { + Check_Type(argv[2], T_STRING); + sep = *(RSTRING(argv[2])->ptr); + } else { + sep = (unsigned char)FIX2LONG(argv[2]); + } + if (sep > 255) + rb_raise(rb_eArgError, "separator code too large (%d for 0..255)", + FIX2LONG(sep)); + case 2: + if (!FIXNUM_P(argv[1])) + rb_raise(rb_eTypeError, "2nd arg %s is not a Fixnum", + STR2CSTR(rb_inspect(argv[1]))); + width = FIX2ULONG(argv[1]); + case 1: + Check_Type(argv[0], T_STRING); + ptr = RSTRING(argv[0])->ptr; + len = RSTRING(argv[0])->len; + if (len > 0 && *ptr == '+') addsign = 1; + if (len > addsign) + for (i = addsign; i < len; i++) + if (!isdigit(ptr[i])) + rb_raise(rb_eArgError, "illegal format %s", + STR2CSTR(rb_inspect(argv[0]))); + k = len+2-addsign; + tmp = ALLOCA_N(char, k); + memcpy(tmp+1, ptr+addsign, len-addsign); + break; + case 0: + k = 2; + tmp = ALLOCA_N(char, k); + break; + default: + rb_raise(rb_eArgError, "too many arguments(%d for 3)", argc); + } + + tmp[0] = '%'; tmp[k-1] = bchar; + if (!RBIGNUM(num)->sign) addsign = 1; + + args = ALLOCA_N(VALUE, 2); + args[0] = rb_str_new(tmp, k); + args[1] = ((!RBIGNUM(num)->sign)?rb_big_uminus(num):num); + buf = rb_f_sprintf(2, args); + len = RSTRING(buf)->len; + ptr = RSTRING(buf)->ptr; + + if (width > 0) { + j = (len-1)/width; + res = ALLOCA_N(char, len+j+addsign); + k = len+j+addsign; + rp = res+addsign; + mod = 0; + for (i = len-1; i > -1; i--) { + if (ptr[i] == ' ') break; + if (mod == width) { + rp[i+j] = sep; + j--; + mod = 0; + } + rp[i+j] = ptr[i]; + mod += 1; + } + if (addsign) res[i+j+1] = (!RBIGNUM(num)->sign)?'-':'+'; + for (i = i+j; i > -1; i--) res[i] = ' '; + return rb_str_new(res,k); + } + + if (!addsign) return buf; + + j = (ptr[0] != ' '); + res = ALLOCA_N(char, len+j); + k = len+j; + memcpy(res+j, ptr, len); + + if (j) { + res[0] = (!RBIGNUM(num)->sign)?'-':'+'; + } else { + tmp = res+len+j; + while (*tmp-- != ' '); + *(tmp+1) = (!RBIGNUM(num)->sign)?'-':'+'; + } + + return rb_str_new(res,k); +} + +static VALUE +rb_big_bin(argc, argv, num) + int argc; + VALUE argv, num; +{ + big_represent('b', num, argc, argv); +} + +static VALUE +rb_big_oct(argc, argv, num) + int argc; + VALUE argv, num; +{ + big_represent('o', num, argc, argv); +} + +static VALUE +rb_big_dec(argc, argv, num) + int argc; + VALUE argv, num; +{ + big_represent('d', num, argc, argv); +} + +static VALUE +rb_big_hex(argc, argv, num) + int argc; + VALUE argv, num; +{ + big_represent('x', num, argc, argv); +} + +static VALUE +rb_big_heX(argc, argv, num) + int argc; + VALUE argv, num; +{ + big_represent('X', num, argc, argv); +} + void Init_Bignum() { @@ -1371,4 +1512,10 @@ rb_define_method(rb_cBignum, "abs", rb_big_abs, 0); rb_define_method(rb_cBignum, "size", rb_big_size, 0); rb_define_method(rb_cBignum, "zero?", rb_big_zero_p, 0); + + rb_define_method(rb_cBignum, "bin", rb_big_bin, -1); + rb_define_method(rb_cBignum, "oct", rb_big_oct, -1); + rb_define_method(rb_cBignum, "dec", rb_big_dec, -1); + rb_define_method(rb_cBignum, "hex", rb_big_hex, -1); + rb_define_method(rb_cBignum, "heX", rb_big_heX, -1); } Index: numeric.c =================================================================== RCS file: /home/cvs/ruby/numeric.c,v retrieving revision 1.7 diff -u -r1.7 numeric.c --- numeric.c 2000/02/01 03:12:08 1.7 +++ numeric.c 2000/02/02 14:32:20 @@ -1448,6 +1448,147 @@ return Qfalse; } +static VALUE +fix_represent(bchar, num, argc, argv) + char bchar; + VALUE num; + int argc; + VALUE *argv; +{ + unsigned int width = 0; + unsigned char sep = '_'; + int addsign = 0; + int i, j, k, len, mod; + char *ptr, *res, *tmp, *rp; + VALUE buf, *args; + + switch (argc) { + case 3: + if (!FIXNUM_P(argv[2])) { + Check_Type(argv[2], T_STRING); + sep = *(RSTRING(argv[2])->ptr); + } else { + sep = (unsigned char)FIX2LONG(argv[2]); + } + if (sep > 255) + rb_raise(rb_eArgError, "separator code too large (%d for 0..255)", + FIX2LONG(sep)); + case 2: + if (!FIXNUM_P(argv[1])) + rb_raise(rb_eTypeError, "2nd arg %s is not a Fixnum", + STR2CSTR(rb_inspect(argv[1]))); + width = FIX2ULONG(argv[1]); + case 1: + Check_Type(argv[0], T_STRING); + ptr = RSTRING(argv[0])->ptr; + len = RSTRING(argv[0])->len; + if (len > 0 && *ptr == '+') addsign = 1; + if (len > addsign) + for (i = addsign; i < len; i++) + if (!isdigit(ptr[i])) + rb_raise(rb_eArgError, "illegal format %s", + STR2CSTR(rb_inspect(argv[0]))); + k = len+2-addsign; + tmp = ALLOCA_N(char, k); + memcpy(tmp+1, ptr+addsign, len-addsign); + break; + case 0: + k = 2; + tmp = ALLOCA_N(char, k); + break; + default: + rb_raise(rb_eArgError, "too many arguments(%d for 3)", argc); + } + + tmp[0] = '%'; tmp[k-1] = bchar; + if (FIX2LONG(num)<0) addsign = 1; + + args = ALLOCA_N(VALUE, 2); + args[0] = rb_str_new(tmp, k); + args[1] = ((FIX2LONG(num)<0)?fix_uminus(num):num); + buf = rb_f_sprintf(2, args); + len = RSTRING(buf)->len; + ptr = RSTRING(buf)->ptr; + + if (width > 0) { + j = (len-1)/width; + res = ALLOCA_N(char, len+j+addsign); + k = len+j+addsign; + rp = res+addsign; + mod = 0; + for (i = len-1; i > -1; i--) { + if (ptr[i] == ' ') break; + if (mod == width) { + rp[i+j] = sep; + j--; + mod = 0; + } + rp[i+j] = ptr[i]; + mod += 1; + } + if (addsign) res[i+j+1] = (FIX2LONG(num)<0)?'-':'+'; + for (i = i+j; i > -1; i--) res[i] = ' '; + return rb_str_new(res,k); + } + + if (!addsign) return buf; + + j = (ptr[0] != ' '); + res = ALLOCA_N(char, len+j); + k = len+j; + memcpy(res+j, ptr, len); + + if (j) { + res[0] = (FIX2LONG(num)<0)?'-':'+'; + } else { + tmp = res+len+j; + while (*tmp-- != ' '); + *(tmp+1) = (FIX2LONG(num)<0)?'-':'+'; + } + + return rb_str_new(res,k); +} + +static VALUE +fix_bin(argc, argv, num) + int argc; + VALUE argv, num; +{ + fix_represent('b', num, argc, argv); +} + +static VALUE +fix_oct(argc, argv, num) + int argc; + VALUE argv, num; +{ + fix_represent('o', num, argc, argv); +} + +static VALUE +fix_dec(argc, argv, num) + int argc; + VALUE argv, num; +{ + fix_represent('d', num, argc, argv); +} + +static VALUE +fix_hex(argc, argv, num) + int argc; + VALUE argv, num; +{ + fix_represent('x', num, argc, argv); +} + +static VALUE +fix_heX(argc, argv, num) + int argc; + VALUE argv, num; +{ + fix_represent('X', num, argc, argv); +} + void Init_Numeric() { @@ -1529,6 +1670,11 @@ rb_define_method(rb_cFixnum, "to_i", fix_to_i, 0); rb_define_method(rb_cFixnum, "to_f", fix_to_f, 0); + rb_define_method(rb_cFixnum, "bin", fix_bin, -1); + rb_define_method(rb_cFixnum, "oct", fix_oct, -1); + rb_define_method(rb_cFixnum, "dec", fix_dec, -1); + rb_define_method(rb_cFixnum, "hex", fix_hex, -1); + rb_define_method(rb_cFixnum, "heX", fix_heX, -1); rb_define_method(rb_cFixnum, "succ", fix_succ, 0); rb_define_method(rb_cFixnum, "next", fix_succ, 0);