ruby-changes:48120
From: naruse <ko1@a...>
Date: Sat, 21 Oct 2017 15:51:07 +0900 (JST)
Subject: [ruby-changes:48120] naruse:r60234 (trunk): [Feature #13712] String#start_with? supports regexp
naruse 2017-10-21 15:51:01 +0900 (Sat, 21 Oct 2017) New Revision: 60234 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=60234 Log: [Feature #13712] String#start_with? supports regexp Modified files: trunk/NEWS trunk/internal.h trunk/re.c trunk/string.c trunk/test/ruby/test_string.rb Index: string.c =================================================================== --- string.c (revision 60233) +++ string.c (revision 60234) @@ -9219,11 +9219,20 @@ rb_str_start_with(int argc, VALUE *argv, https://github.com/ruby/ruby/blob/trunk/string.c#L9219 for (i=0; i<argc; i++) { VALUE tmp = argv[i]; - StringValue(tmp); - rb_enc_check(str, tmp); - if (RSTRING_LEN(str) < RSTRING_LEN(tmp)) continue; - if (memcmp(RSTRING_PTR(str), RSTRING_PTR(tmp), RSTRING_LEN(tmp)) == 0) - return Qtrue; + switch (TYPE(tmp)) { + case T_REGEXP: + { + bool r = rb_reg_start_with_p(tmp, str); + if (r) return Qtrue; + } + break; + default: + StringValue(tmp); + rb_enc_check(str, tmp); + if (RSTRING_LEN(str) < RSTRING_LEN(tmp)) continue; + if (memcmp(RSTRING_PTR(str), RSTRING_PTR(tmp), RSTRING_LEN(tmp)) == 0) + return Qtrue; + } } return Qfalse; } Index: test/ruby/test_string.rb =================================================================== --- test/ruby/test_string.rb (revision 60233) +++ test/ruby/test_string.rb (revision 60234) @@ -1723,6 +1723,11 @@ CODE https://github.com/ruby/ruby/blob/trunk/test/ruby/test_string.rb#L1723 bug5536 = '[ruby-core:40623]' assert_raise(TypeError, bug5536) {S("str").start_with? :not_convertible_to_string} + + assert_equal(true, "hello".start_with?(/hel/)) + assert_equal("hel", $&) + assert_equal(false, "hello".start_with?(/el/)) + assert_nil($&) end def test_strip Index: re.c =================================================================== --- re.c (revision 60233) +++ re.c (revision 60234) @@ -1580,6 +1580,83 @@ rb_reg_search(VALUE re, VALUE str, long https://github.com/ruby/ruby/blob/trunk/re.c#L1580 return rb_reg_search0(re, str, pos, reverse, 1); } +bool +rb_reg_start_with_p(VALUE re, VALUE str) +{ + long result; + VALUE match; + struct re_registers regi, *regs = ®i; + regex_t *reg; + int tmpreg; + onig_errmsg_buffer err = ""; + + reg = rb_reg_prepare_re0(re, str, err); + tmpreg = reg != RREGEXP_PTR(re); + if (!tmpreg) RREGEXP(re)->usecnt++; + + match = rb_backref_get(); + if (!NIL_P(match)) { + if (FL_TEST(match, MATCH_BUSY)) { + match = Qnil; + } + else { + regs = RMATCH_REGS(match); + } + } + if (NIL_P(match)) { + MEMZERO(regs, struct re_registers, 1); + } + result = onig_match(reg, + (UChar*)(RSTRING_PTR(str)), + ((UChar*)(RSTRING_PTR(str)) + RSTRING_LEN(str)), + (UChar*)(RSTRING_PTR(str)), + regs, ONIG_OPTION_NONE); + if (!tmpreg) RREGEXP(re)->usecnt--; + if (tmpreg) { + if (RREGEXP(re)->usecnt) { + onig_free(reg); + } + else { + onig_free(RREGEXP_PTR(re)); + RREGEXP_PTR(re) = reg; + } + } + if (result < 0) { + if (regs == ®i) + onig_region_free(regs, 0); + if (result == ONIG_MISMATCH) { + rb_backref_set(Qnil); + return false; + } + else { + onig_error_code_to_str((UChar*)err, (int)result); + rb_reg_raise(RREGEXP_SRC_PTR(re), RREGEXP_SRC_LEN(re), err, re); + } + } + + if (NIL_P(match)) { + int err; + match = match_alloc(rb_cMatch); + err = rb_reg_region_copy(RMATCH_REGS(match), regs); + onig_region_free(regs, 0); + if (err) rb_memerror(); + } + else { + FL_UNSET(match, FL_TAINT); + } + + RMATCH(match)->str = rb_str_new4(str); + OBJ_INFECT(match, str); + + RMATCH(match)->regexp = re; + RMATCH(match)->rmatch->char_offset_updated = 0; + rb_backref_set(match); + + OBJ_INFECT(match, re); + + return true; +} + VALUE rb_reg_nth_defined(int nth, VALUE match) { Index: internal.h =================================================================== --- internal.h (revision 60233) +++ internal.h (revision 60234) @@ -1570,6 +1570,7 @@ VALUE rb_reg_compile(VALUE str, int opti https://github.com/ruby/ruby/blob/trunk/internal.h#L1570 VALUE rb_reg_check_preprocess(VALUE); long rb_reg_search0(VALUE, VALUE, long, int, int); VALUE rb_reg_match_p(VALUE re, VALUE str, long pos); +bool rb_reg_start_with_p(VALUE re, VALUE str); void rb_backref_set_string(VALUE string, long pos, long len); int rb_match_count(VALUE match); int rb_match_nth_defined(int nth, VALUE match); Index: NEWS =================================================================== --- NEWS (revision 60233) +++ NEWS (revision 60234) @@ -108,6 +108,7 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L108 * String#delete_suffix! is added to remove suffix destructively [Feature #13665] * String#each_grapheme_cluster and String#grapheme_clusters is added to enumerate grapheme clusters [Feature #13780] + * String#start_with? supports regexp [Feature #13712] * Regexp/String: Updated Unicode version from 9.0.0 to 10.0.0 [Feature #13685] -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/