From: Minero Aoki Date: 2000-09-21T02:44:32+09:00 Subject: [ruby-dev:10988] [patch] String#index( sub, pos, range ) あおきです。 ちょっと前に話題にした String#index に範囲の第三引数をつける案を 実装してみたので検討してもらえないでしょうか。もちろん 1.7 でいいです。 欲しい理由は、低負荷でお手軽なスキャンに不可欠だからです。 (でも本当は Regexp#match に開始地点と範囲の引数がついててほしい…) ------------------------------------------------------------------- あおきみねろう Thu Sep 21 02:40:54 2000 Minero Aoki * string.c, re.c: String#index takes third argument "range". Index: string.c =================================================================== RCS file: /home/cvs/ruby/string.c,v retrieving revision 1.44 diff -u -r1.44 string.c --- string.c 2000/09/07 06:59:36 1.44 +++ string.c 2000/09/19 17:01:30 @@ -614,9 +614,9 @@ } static long -rb_str_index(str, sub, offset) +rb_str_index_range(str, sub, offset, range) VALUE str, sub; - long offset; + long offset, range; { char *s, *e, *p; long len; @@ -630,7 +630,7 @@ p = RSTRING(sub)->ptr; len = RSTRING(sub)->len; if (len == 0) return offset; - e = RSTRING(str)->ptr + RSTRING(str)->len - len + 1; + e = RSTRING(str)->ptr + offset + range - len + 1; while (s < e) { if (rb_memcmp(s, p, len) == 0) { return (s-(RSTRING(str)->ptr)); @@ -640,6 +640,70 @@ return -1; } +#define rb_str_index(str, sub, off) \ + rb_str_index_range(str, sub , off, RSTRING(str)->len - off) + +static long +rb_str_rindex_range(str, sub, offset, range) + VALUE str, sub; + long offset, range; +{ + int len; + char *s, *sbeg, *t; + + len = RSTRING(sub)->len; + /* substring longer than string */ + if (RSTRING(str)->len < len) return Qnil; + if (RSTRING(str)->len - offset < len) { + offset = RSTRING(str)->len - len; + } + sbeg = RSTRING(str)->ptr + offset - range; + s = RSTRING(str)->ptr + offset; + t = RSTRING(sub)->ptr; + if (len) { + while (sbeg <= s) { + if (rb_memcmp(s, t, len) == 0) { + return s - RSTRING(str)->ptr; + } + s--; + } + } + else { + return offset; + } + return -1; +} + +static VALUE +rb_str_chr(str, c, pos, range) + VALUE str; + int c; + long pos, range; +{ + char *p = RSTRING(str)->ptr; + long end = pos + range; + + for (; pos < end; pos++) { + if (p[pos] == c) return INT2NUM(pos); + } + return Qnil; +} + +static VALUE +rb_str_rchr(str, c, pos, range) + VALUE str; + int c; + long pos, range; +{ + char *p = RSTRING(str)->ptr; + long end = pos - range; + + for (; pos >= end; pos--) { + if (p[pos] == c) return INT2NUM(pos); + } + return Qnil; +} + static VALUE rb_str_index_m(argc, argv, str) int argc; @@ -648,40 +712,50 @@ { VALUE sub; VALUE initpos; - long pos; - - if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) { + VALUE initrg; + long pos = 0; + long range = 0; + + pos = 0; + range = RSTRING(str)->len; + switch (rb_scan_args(argc, argv, "12", &sub, &initpos, &initrg)) { + case 3: + range = NUM2LONG(initrg); + case 2: pos = NUM2LONG(initpos); - } - else { - pos = 0; + default: + break; } if (pos < 0) { pos += RSTRING(str)->len; if (pos < 0) return Qnil; } + if (pos > RSTRING(str)->len) return Qnil; + if (pos + range > RSTRING(str)->len) { + range = RSTRING(str)->len - pos; + } + else if (pos + range < 0) { + range = -pos; + } switch (TYPE(sub)) { case T_REGEXP: pos = rb_reg_adjust_startpos(sub, str, pos, 0); - pos = rb_reg_search(sub, str, pos, 0); + pos = rb_reg_search_range(sub, str, pos, range); break; case T_STRING: - pos = rb_str_index(str, sub, pos); + if (range >= 0) + pos = rb_str_index_range(str, sub, pos, range); + else + pos = rb_str_rindex_range(str, sub, pos, -range); break; case T_FIXNUM: - { - int c = FIX2INT(sub); - long len = RSTRING(str)->len; - char *p = RSTRING(str)->ptr; - - for (;pos= 0) + return rb_str_chr(str, FIX2INT(sub), pos, range); + else + return rb_str_rchr(str, FIX2INT(sub), pos, -range); default: rb_raise(rb_eTypeError, "type mismatch: %s given", @@ -693,78 +767,64 @@ } static VALUE -rb_str_rindex(argc, argv, str) +rb_str_rindex_m(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE sub; - VALUE position; - int pos, len; - char *s, *sbeg, *t; + VALUE initpos; + VALUE initrg; + long pos; + long range; - if (rb_scan_args(argc, argv, "11", &sub, &position) == 2) { - pos = NUM2INT(position); - if (pos < 0) { - pos += RSTRING(str)->len; - if (pos < 0) return Qnil; - } - if (pos > RSTRING(str)->len) pos = RSTRING(str)->len; + pos = range = RSTRING(str)->len; + switch (rb_scan_args(argc, argv, "12", &sub, &initpos, &initrg)) { + case 3: + range = NUM2LONG(initrg); + case 2: + pos = NUM2INT(initpos); + default: + break; } - else { - pos = RSTRING(str)->len; + if (pos < 0) { + pos += RSTRING(str)->len; + if (pos < 0) return Qnil; } + if (pos > RSTRING(str)->len) + pos = RSTRING(str)->len; + if (pos - range < 0) + range = pos; + if (pos - range > RSTRING(str)->len) + range = pos - RSTRING(str)->len; switch (TYPE(sub)) { case T_REGEXP: if (RREGEXP(sub)->len) { pos = rb_reg_adjust_startpos(sub, str, pos, 1); - pos = rb_reg_search(sub, str, pos, 1); + pos = rb_reg_search_range(sub, str, pos, -range); } - if (pos >= 0) return INT2NUM(pos); break; case T_STRING: - len = RSTRING(sub)->len; - /* substring longer than string */ - if (RSTRING(str)->len < len) return Qnil; - if (RSTRING(str)->len - pos < len) { - pos = RSTRING(str)->len - len; - } - sbeg = RSTRING(str)->ptr; - s = RSTRING(str)->ptr + pos; - t = RSTRING(sub)->ptr; - if (len) { - while (sbeg <= s) { - if (rb_memcmp(s, t, len) == 0) { - return INT2NUM(s - RSTRING(str)->ptr); - } - s--; - } - } - else { - return INT2NUM(pos); - } + if (range >= 0) + pos = rb_str_rindex_range(str, sub, pos, range); + else + pos = rb_str_index_range(str, sub, pos, range); break; case T_FIXNUM: - { - int c = FIX2INT(sub); - char *p = RSTRING(str)->ptr + pos; - char *pbeg = RSTRING(str)->ptr; - - while (pbeg <= p) { - if (*p == c) return INT2NUM(p - RSTRING(str)->ptr); - p--; - } - return Qnil; - } + if (range >= 0) + return rb_str_rchr(str, FIX2INT(sub), pos, range); + else + return rb_str_chr(str, FIX2INT(sub), pos, -range); default: rb_raise(rb_eTypeError, "type mismatch: %s given", rb_class2name(CLASS_OF(sub))); } - return Qnil; + if (pos < 0) return Qnil; + return INT2NUM(pos); } static char @@ -2804,7 +2864,7 @@ rb_define_method(rb_cString, "next!", rb_str_succ_bang, 0); rb_define_method(rb_cString, "upto", rb_str_upto_m, 1); rb_define_method(rb_cString, "index", rb_str_index_m, -1); - rb_define_method(rb_cString, "rindex", rb_str_rindex, -1); + rb_define_method(rb_cString, "rindex", rb_str_rindex_m, -1); rb_define_method(rb_cString, "replace", rb_str_replace_m, 1); rb_define_method(rb_cString, "to_i", rb_str_to_i, 0); Index: re.c =================================================================== RCS file: /home/cvs/ruby/re.c,v retrieving revision 1.32 diff -u -r1.32 re.c --- re.c 2000/09/01 09:18:11 1.32 +++ re.c 2000/09/19 17:01:34 @@ -586,14 +586,13 @@ } int -rb_reg_search(re, str, pos, reverse) +rb_reg_search_range(re, str, pos, range) VALUE re, str; - int pos, reverse; + int pos, range; { int result; VALUE match; static struct re_registers regs; - int range; if (pos > RSTRING(str)->len) return -1; @@ -605,12 +604,6 @@ else if (reg_kcode != curr_kcode) kcode_reset_option(); - if (reverse) { - range = -pos; - } - else { - range = RSTRING(str)->len - pos; - } result = re_search(RREGEXP(re)->ptr,RSTRING(str)->ptr,RSTRING(str)->len, pos, range, ®s); @@ -643,6 +636,15 @@ OBJ_INFECT(match, re); OBJ_INFECT(match, str); return result; +} + +int +rb_reg_search(re, str, pos, reverse) + VALUE re, str; + int pos, reverse; +{ + rb_reg_search_range(re, str, pos, + reverse ? -pos : RSTRING(str)->len - pos); } VALUE