1616#include "encindex.h"
1717#include "hrtime.h"
1818#include "internal.h"
19+ #include "internal/bignum.h"
1920#include "internal/encoding.h"
2021#include "internal/error.h"
2122#include "internal/hash.h"
@@ -1187,7 +1188,7 @@ match_size(VALUE match)
11871188 return INT2FIX (RMATCH_REGS (match )-> num_regs );
11881189}
11891190
1190- static int name_to_backref_number (struct re_registers * , VALUE , const char * , const char * );
1191+ static int name_to_backref_number (const struct re_registers * , VALUE , const char * , const char * );
11911192NORETURN (static void name_to_backref_error (VALUE name ));
11921193
11931194static void
@@ -2147,7 +2148,7 @@ match_captures(VALUE match)
21472148}
21482149
21492150static int
2150- name_to_backref_number (struct re_registers * regs , VALUE regexp , const char * name , const char * name_end )
2151+ name_to_backref_number (const struct re_registers * regs , VALUE regexp , const char * name , const char * name_end )
21512152{
21522153 if (NIL_P (regexp )) return -1 ;
21532154 return onig_name_to_backref_number (RREGEXP_PTR (regexp ),
@@ -2160,7 +2161,7 @@ name_to_backref_number(struct re_registers *regs, VALUE regexp, const char* name
21602161 name_to_backref_number((regs), (re), (name_ptr), (name_end)))
21612162
21622163static int
2163- namev_to_backref_number (struct re_registers * regs , VALUE re , VALUE name )
2164+ namev_to_backref_number (const struct re_registers * regs , VALUE re , VALUE name )
21642165{
21652166 int num ;
21662167
@@ -3629,6 +3630,76 @@ match_equal(VALUE match1, VALUE match2)
36293630 return Qtrue ;
36303631}
36313632
3633+ /*
3634+ * call-seq:
3635+ * integer_at(index, base = 10) -> integer or nil
3636+ * integer_at(name, base = 10) -> integer or nil
3637+ *
3638+ * Converts the matched substring to integer and return the result.
3639+ * +$~.integer_at(N)+ is equivalent to +$N&.to_i+.
3640+ *
3641+ * m = /(\d+{4})(\d+{2})(\d+{2})/.match("20260308")
3642+ * # => #<MatchData "20260308" 1:"2026" 2:"03" 3:"08">
3643+ * m.integer_at(0) # => 20260308
3644+ * m.integer_at(1) # => 2026
3645+ * m.integer_at(2) # => 3
3646+ * m.integer_at(3) # => 8
3647+ *
3648+ * m = /(?<y>\d+{4})(?<m>\d+{2})(?<d>\d+{2})/.match("20260308")
3649+ * m.integer_at("y") # => 2026
3650+ * m.integer_at("m") # => 3
3651+ * m.integer_at("d") # => 8
3652+ *
3653+ * If the substring does not match, returns +nil+.
3654+ *
3655+ * re = /(\d+)?/
3656+ * re.match("123").integer_at(1) #=> 123
3657+ * re.match("abc").integer_at(1) #=> nil
3658+ *
3659+ * The string is converted in decimal by default.
3660+ *
3661+ * /\d+/.match("011").integer_at(0) #=> 10
3662+ * /\d+/.match("011").integer_at(0, 12) #=> 13
3663+ * /\d+/.match("011").integer_at(0, 0) #=> 9
3664+ *
3665+ * See also MatchData#[], String#to_i.
3666+ */
3667+ static VALUE
3668+ match_integer_at (int argc , VALUE * argv , VALUE match )
3669+ {
3670+ const struct re_registers * regs = RMATCH_REGS (match_check (match ));
3671+
3672+ int base = 10 ;
3673+ VALUE idx ;
3674+ long nth ;
3675+
3676+ argc = rb_check_arity (argc , 1 , 2 );
3677+ if (FIXNUM_P (idx = argv [0 ])) {
3678+ nth = NUM2INT (idx );
3679+ }
3680+ else if ((nth = namev_to_backref_number (regs , RMATCH (match )-> regexp , idx )) < 0 ) {
3681+ name_to_backref_error (idx );
3682+ }
3683+
3684+ if (argc > 1 && (base = NUM2INT (argv [1 ])) < 0 ) {
3685+ rb_raise (rb_eArgError , "invalid radix %d" , base );
3686+ }
3687+
3688+ if (nth >= regs -> num_regs ) return Qnil ;
3689+ if (nth < 0 && (nth += regs -> num_regs ) <= 0 ) return Qnil ;
3690+
3691+ long start = BEG (nth ), end = END (nth );
3692+ if (start < 0 ) return Qnil ;
3693+ RUBY_ASSERT (start <= end , "%ld > %ld" , start , end );
3694+
3695+ VALUE str = RMATCH (match )-> str ;
3696+ RUBY_ASSERT (end <= RSTRING_LEN (str ), "%ld > %ld" , end , RSTRING_LEN (str ));
3697+
3698+ char * endp ;
3699+ return rb_int_parse_cstr (RSTRING_PTR (str ) + start , end - start , & endp , NULL ,
3700+ base , RB_INT_PARSE_DEFAULT );
3701+ }
3702+
36323703static VALUE
36333704reg_operand (VALUE s , int check )
36343705{
@@ -4908,4 +4979,5 @@ Init_Regexp(void)
49084979 rb_define_method (rb_cMatch , "hash" , match_hash , 0 );
49094980 rb_define_method (rb_cMatch , "eql?" , match_equal , 1 );
49104981 rb_define_method (rb_cMatch , "==" , match_equal , 1 );
4982+ rb_define_method (rb_cMatch , "integer_at" , match_integer_at , -1 );
49114983}
0 commit comments