[前][次][番号順一覧][スレッド一覧]

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 = &regi;
+    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 == &regi)
+	    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/

[前][次][番号順一覧][スレッド一覧]