From: Minero Aoki Date: 2001-09-03T22:15:42+09:00 Subject: [ruby-dev:14636] Re: [REQ] String#slice(re, n) あおきです。ruby-dev に移します。 In mail "[ruby-list:31213] Re: [REQ] String#slice(re, n)" matz@ruby-lang.org (Yukihiro Matsumoto) wrote: > まつもと ゆきひろです > |> str.slice(re, n)はマッチしていない、あるいは対応するかっこが > |> ないときにはnilを返すということ? > そうなると(そうでなくてもsliceという名前なら)整合性のために、 > []や[]=やslice!も(re, n)というパターンに対応する必要がありま > すね。大仕事だなあ。 実装してみようかと思ったんですが、その途中で、/a(b)c/ で b に 「マッチ」するような「サブパターンオブジェクト」があるといろいろな 面でうまくいくのではないかと思いつきました。つまり str = 'abc' re = /a(b)c/ n = 1 pat = re.sub_pattern(n) # または RegexpSubPattern.new(re,n) p str.slice(pat) #=> "b" p str.slice!(pat) #=> "ac" p str[pat] #=> "b" p str[pat] = 'REPLACE' #=> "aREPLACEc" という感じです。C からも部分文字列取り出しを透過にしておけば、 string.c は全くいじらずに slice(!) [] []= sub(!) に対応できて しまいます (意見ころころ変えてすみません〜)。 # ただ gsub は offset==BEG[0] を仮定してるらしいので直す必要あり で、それを実装してみたのが添付のパッチです。re.c のレベルで m[i] を m[i-n] に置きかえることで実現してます。struct RRegexp に メンバを増やしてるのは試験実装ってことで許してください。 ------------------------------------------------------------------- 青木峰郎 Index: ruby.h =================================================================== RCS file: /src/ruby/ruby.h,v retrieving revision 1.51 diff -u -r1.51 ruby.h --- ruby.h 2001/07/19 02:46:28 1.51 +++ ruby.h 2001/09/03 12:21:37 @@ -287,6 +287,7 @@ struct re_pattern_buffer *ptr; long len; char *str; + int shift; }; struct RHash { Index: re.c =================================================================== RCS file: /src/ruby/re.c,v retrieving revision 1.44 diff -u -r1.44 re.c --- re.c 2001/07/24 09:07:33 1.44 +++ re.c 2001/09/03 12:21:36 @@ -603,6 +603,9 @@ pos, range); } +static int reg_subpattern_n_get _((VALUE)); +static void match_shift_registers _((VALUE, int)); + int rb_reg_search(re, str, pos, reverse) VALUE re, str; @@ -655,6 +658,7 @@ match = match_alloc(); } re_copy_registers(RMATCH(match)->regs, ®s); + match_shift_registers(match, reg_subpattern_n_get(re)); RMATCH(match)->str = rb_str_new4(str); rb_backref_set(match); @@ -815,6 +819,7 @@ } VALUE rb_cRegexp; +static void reg_subpattern_n_set _((VALUE, int)); static void rb_reg_initialize(obj, s, len, options) @@ -867,6 +872,7 @@ memcpy(re->str, s, len); re->str[len] = '\0'; re->len = len; + reg_subpattern_n_set((VALUE)re, 0); if (options & ~0xf) { kcode_reset_option(); } @@ -1353,6 +1359,55 @@ return match_getter(); } +VALUE rb_cRegexpSubPattern; + +static void +reg_subpattern_n_set(re, nth) + VALUE re; + int nth; +{ + RREGEXP(re)->shift = nth; +} + +static int +reg_subpattern_n_get(re) + VALUE re; +{ + return RREGEXP(re)->shift; +} + +static VALUE +rb_reg_sub_pattern(re, nth) + VALUE re, nth; +{ + VALUE obj; + + obj = rb_reg_clone(re); + RREGEXP(obj)->basic.klass = rb_cRegexpSubPattern; + reg_subpattern_n_set(obj, NUM2INT(nth)); + return obj; +} + +static void +match_shift_registers(match, n) + VALUE match; + int n; +{ + int i; + int len = RMATCH(match)->regs->num_regs; + + if (n > len) n = len; + for (i = 0; i < len - n; i++) { + RMATCH(match)->regs->beg[i] = RMATCH(match)->regs->beg[i+n]; + RMATCH(match)->regs->end[i] = RMATCH(match)->regs->end[i+n]; + } + for (i = len - n; i < len; i++) { + RMATCH(match)->regs->beg[i] = -1; + RMATCH(match)->regs->end[i] = -1; + } + RMATCH(match)->regs->num_regs -= n; +} + void Init_Regexp() { @@ -1408,6 +1463,9 @@ rb_define_const(rb_cRegexp, "MULTILINE", INT2FIX(RE_OPTION_MULTILINE)); rb_global_variable(®_cache); + + rb_cRegexpSubPattern = rb_define_class("RegexpSubPattern", rb_cRegexp); + rb_define_method(rb_cRegexp, "sub_pattern", rb_reg_sub_pattern, 1); rb_cMatch = rb_define_class("MatchData", rb_cObject); rb_define_global_const("MatchingData", rb_cMatch);