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

ruby-changes:2667

From: ko1@a...
Date: 9 Dec 2007 16:13:12 +0900
Subject: [ruby-changes:2667] akr - Ruby:r14158 (trunk): * re.c (match_backref_number): new function for converting a backref

akr	2007-12-09 16:12:44 +0900 (Sun, 09 Dec 2007)

  New Revision: 14158

  Modified files:
    trunk/ChangeLog
    trunk/re.c
    trunk/test/ruby/test_regexp.rb

  Log:
    * re.c (match_backref_number): new function for converting a backref
      name/number to an integer.
      (match_offset): use match_backref_number.
      (match_begin): ditto.
      (match_end): ditto.
      (name_to_backref_number): raise IndexError instead of RuntimeError.
      (match_inspect): show capture index.


  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=14158&r2=14157
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/ruby/test_regexp.rb?r1=14158&r2=14157
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/re.c?r1=14158&r2=14157

Index: re.c
===================================================================
--- re.c	(revision 14157)
+++ re.c	(revision 14158)
@@ -621,7 +621,41 @@
     return INT2FIX(i);
 }
 
+static int
+match_backref_number(VALUE match, VALUE backref)
+{
+    const char *name;
+    int num;
 
+    struct re_registers *regs = RMATCH(match)->regs;
+    VALUE regexp = RMATCH(match)->regexp;
+
+    switch(TYPE(backref)) {
+      default:
+        return NUM2INT(backref);
+
+      case T_SYMBOL:
+        name = rb_id2name(SYM2ID(backref));
+        break;
+
+      case T_STRING:
+        name = StringValueCStr(backref);
+        break;
+    }
+
+    num = onig_name_to_backref_number(RREGEXP(regexp)->ptr,
+              (const unsigned char*)name,
+              (const unsigned char*)name + strlen(name),
+              regs);
+
+    if (num < 1) {
+        rb_raise(rb_eIndexError, "undefined group name reference: %s", name);
+    }
+
+    return num;
+}
+
+
 /*
  *  call-seq:
  *     mtch.offset(n)   => array
@@ -637,7 +671,7 @@
 static VALUE
 match_offset(VALUE match, VALUE n)
 {
-    int i = NUM2INT(n);
+    int i = match_backref_number(match, n);
 
     if (i < 0 || RMATCH(match)->regs->num_regs <= i)
 	rb_raise(rb_eIndexError, "index %d out of matches", i);
@@ -665,7 +699,7 @@
 static VALUE
 match_begin(VALUE match, VALUE n)
 {
-    int i = NUM2INT(n);
+    int i = match_backref_number(match, n);
 
     if (i < 0 || RMATCH(match)->regs->num_regs <= i)
 	rb_raise(rb_eIndexError, "index %d out of matches", i);
@@ -692,7 +726,7 @@
 static VALUE
 match_end(VALUE match, VALUE n)
 {
-    int i = NUM2INT(n);
+    int i = match_backref_number(match, n);
 
     if (i < 0 || RMATCH(match)->regs->num_regs <= i)
 	rb_raise(rb_eIndexError, "index %d out of matches", i);
@@ -1090,8 +1124,8 @@
   }
   else {
     VALUE s = rb_str_new(name, (long )(name_end - name));
-    rb_raise(rb_eRuntimeError, "undefined group name reference: %s",
-                                StringValuePtr(s));
+    rb_raise(rb_eIndexError, "undefined group name reference: %s",
+                             StringValuePtr(s));
   }
 }
 
@@ -1225,6 +1259,25 @@
     return RMATCH(match)->str;	/* str is frozen */
 }
 
+struct backref_name_tag {
+    const UChar *name;
+    long len;
+};
+
+static int
+match_inspect_name_iter(const OnigUChar *name, const OnigUChar *name_end,
+          int back_num, int *back_refs, OnigRegex regex, void *arg0)
+{
+    struct backref_name_tag *arg = (struct backref_name_tag *)arg0;
+    int i;
+
+    for (i = 0; i < back_num; i++) {
+        arg[back_refs[i]].name = name;
+        arg[back_refs[i]].len = name_end - name;
+    }
+    return 0;
+}
+
 /*
  * call-seq:
  *    mtch.inspect   => str
@@ -1244,13 +1297,31 @@
     char *cname = rb_obj_classname(match);
     VALUE str;
     int i;
+    int num_regs = RMATCH(match)->regs->num_regs;
+    struct backref_name_tag *names;
 
+    names = ALLOCA_N(struct backref_name_tag, num_regs);
+    MEMZERO(names, struct backref_name_tag, num_regs);
+
+    onig_foreach_name(RREGEXP(RMATCH(match)->regexp)->ptr,
+            match_inspect_name_iter, names);
+
     str = rb_str_buf_new2("#<");
     rb_str_buf_cat2(str, cname);
 
-    for (i = 0; i < RMATCH(match)->regs->num_regs; i++) {
+    for (i = 0; i < num_regs; i++) {
         VALUE v;
         rb_str_buf_cat2(str, " ");
+        if (0 < i) {
+            if (names[i].name)
+                rb_str_buf_cat(str, (const char *)names[i].name, names[i].len);
+            else {
+                char buf[sizeof(i)*3+1];
+                snprintf(buf, sizeof(buf), "%d", i);
+                rb_str_buf_cat2(str, buf);
+            }
+            rb_str_buf_cat2(str, ":");
+        }
         v = rb_reg_nth_match(i, match);
         if (v == Qnil)
             rb_str_buf_cat2(str, "nil");
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 14157)
+++ ChangeLog	(revision 14158)
@@ -1,3 +1,13 @@
+Sun Dec  9 15:57:53 2007  Tanaka Akira  <akr@f...>
+
+	* re.c (match_backref_number): new function for converting a backref
+	  name/number to an integer.
+	  (match_offset): use match_backref_number.
+	  (match_begin): ditto.
+	  (match_end): ditto.
+	  (name_to_backref_number): raise IndexError instead of RuntimeError.
+	  (match_inspect): show capture index.
+
 Sun Dec  9 14:59:15 2007  Koichi Sasada  <ko1@a...>
 
 	* eval_intern.h (CHECK_STACK_OVERFLOW): reserve frame size.
Index: test/ruby/test_regexp.rb
===================================================================
--- test/ruby/test_regexp.rb	(revision 14157)
+++ test/ruby/test_regexp.rb	(revision 14158)
@@ -49,4 +49,27 @@
       :ok
     end
   end
+
+  def test_named_capture
+    m = /&(?<foo>.*?);/.match("aaa &amp; yyy")
+    assert_equal("amp", m["foo"])
+    assert_equal("amp", m[:foo])
+    assert_equal(5, m.begin(:foo))
+    assert_equal(8, m.end(:foo))
+    assert_equal([5,8], m.offset(:foo))
+    #assert_equal(["amp"], m.values_at(:foo))
+
+    assert_equal("aaa [amp] yyy", "aaa &amp; yyy".sub(/&(?<foo>.*?);/, '[\k<foo>]'))
+
+    assert_equal('#<MatchData "&amp; y" foo:"amp">',
+      /&(?<foo>.*?); (y)/.match("aaa &amp; yyy").inspect)
+    assert_equal('#<MatchData "&amp; y" 1:"amp" 2:"y">',
+      /&(.*?); (y)/.match("aaa &amp; yyy").inspect)
+    assert_equal('#<MatchData "&amp; y" foo:"amp" bar:"y">',
+      /&(?<foo>.*?); (?<bar>y)/.match("aaa &amp; yyy").inspect)
+    assert_equal('#<MatchData "&amp; y" foo:"amp" foo:"y">',
+      /&(?<foo>.*?); (?<foo>y)/.match("aaa &amp; yyy").inspect)
+
+    # MatchData#keys
+  end
 end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml

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