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

ruby-changes:2672

From: ko1@a...
Date: 10 Dec 2007 06:44:59 +0900
Subject: [ruby-changes:2672] akr - Ruby:r14163 (trunk): * re.c (rb_reg_names): new method Regexp#names.

akr	2007-12-10 06:44:19 +0900 (Mon, 10 Dec 2007)

  New Revision: 14163

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

  Log:
    * re.c (rb_reg_names): new method Regexp#names.
      (rb_reg_named_captures): new method Regexp#named_captures
      (match_regexp): new method MatchData#regexp.
      (match_names): new method MatchData#names.
    
    * lib/pp.rb (MatchData#pretty_print): show names of named captures.


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

Index: re.c
===================================================================
--- re.c	(revision 14162)
+++ re.c	(revision 14163)
@@ -523,7 +523,85 @@
     return INT2NUM(options);
 }
 
+static int
+reg_names_iter(const OnigUChar *name, const OnigUChar *name_end,
+          int back_num, int *back_refs, OnigRegex regex, void *arg)
+{
+    VALUE ary = (VALUE)arg;
+    rb_ary_push(ary, rb_str_new((const char *)name, name_end-name));
+    return 0;
+}
 
+/*
+ * call-seq:
+ *    rxp.names   => [name1, name2, ...]
+ *
+ * Returns a list of names of captures as an array of strings.
+ *
+ *     /(?<foo>.)(?<bar>.)(?<baz>.)/.names
+ *     #=> ["foo", "bar", "baz"]
+ *
+ *     /(?<foo>.)(?<foo>.)/.names
+ *     #=> ["foo"]
+ *
+ *     /(.)(.)/.names' 
+ *     #=> []
+ */
+
+static VALUE
+rb_reg_names(VALUE re)
+{
+    VALUE ary = rb_ary_new();
+    onig_foreach_name(RREGEXP(re)->ptr, reg_names_iter, (void*)ary);
+    return ary;
+}
+
+static int
+reg_named_captures_iter(const OnigUChar *name, const OnigUChar *name_end,
+          int back_num, int *back_refs, OnigRegex regex, void *arg)
+{
+    VALUE hash = (VALUE)arg;
+    VALUE ary = rb_ary_new2(back_num);
+    int i;
+
+    for(i = 0; i < back_num; i++)
+        rb_ary_store(ary, i, INT2NUM(back_refs[i]));
+
+    rb_hash_aset(hash, rb_str_new((const char*)name, name_end-name),ary);
+
+    return 0;
+}
+
+/*
+ * call-seq:
+ *    rxp.named_captures  => hash
+ *
+ * Returns a hash representing information about named captures of <i>rxp</i>.
+ *
+ * A key of the hash is a name of the named captures.
+ * A value of the hash is an array which is list of indexes of corresponding
+ * named captures.
+ * 
+ *    /(?<foo>.)(?<bar>.)/.named_captures
+ *    #=> {"foo"=>[1], "bar"=>[2]}
+ *
+ *    /(?<foo>.)(?<foo>.)/.named_captures'
+ *    #=> {"foo"=>[1, 2]}
+ *
+ * If there are no named captures, an empty hash is returned.
+ *
+ *    /(.)(.)/.named_captures' 
+ *    #=> {}
+ */
+
+static VALUE
+rb_reg_named_captures(VALUE re)
+{
+    VALUE hash = rb_hash_new();
+    onig_foreach_name(RREGEXP(re)->ptr, reg_named_captures_iter, (void*)hash);
+    return hash;
+}
+
 static Regexp*
 make_regexp(const char *s, long len, rb_encoding *enc, int flags, onig_errmsg_buffer err)
 {
@@ -604,6 +682,42 @@
 
 
 /*
+ * call-seq:
+ *    mtch.regexp   => regexp
+ *
+ * Returns the regexp.
+ *
+ *     m = /a.*b/.match("abc")
+ *     m.regexp #=> /a.*b/
+ */
+
+static VALUE
+match_regexp(VALUE match)
+{
+    return RMATCH(match)->regexp;
+}
+
+/*
+ * call-seq:
+ *    mtch.names   => [name1, name2, ...]
+ *
+ * Returns a list of names of captures as an array of strings.
+ * It is same as mtch.regexp.names.
+ *
+ *     /(?<foo>.)(?<bar>.)(?<baz>.)/.match("hoge").names
+ *     #=> ["foo", "bar", "baz"]
+ *
+ *     m = /(?<x>.)(?<y>.)?/.match("a") #=> #<MatchData "a" x:"a" y:nil>
+ *     m.names                          #=> ["x", "y"]
+ */
+
+static VALUE
+match_names(VALUE match)
+{
+    return rb_reg_names(RMATCH(match)->regexp);
+}
+
+/*
  *  call-seq:
  *     mtch.length   => integer
  *     mtch.size     => integer
@@ -1362,11 +1476,12 @@
     int i;
     int num_regs = RMATCH(match)->regs->num_regs;
     struct backref_name_tag *names;
+    VALUE regexp = RMATCH(match)->regexp;
 
     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,
+    onig_foreach_name(RREGEXP(regexp)->ptr,
             match_inspect_name_iter, names);
 
     str = rb_str_buf_new2("#<");
@@ -2818,6 +2933,8 @@
     rb_define_method(rb_cRegexp, "options", rb_reg_options_m, 0);
     rb_define_method(rb_cRegexp, "encoding", rb_obj_encoding, 0); /* in encoding.c */
     rb_define_method(rb_cRegexp, "fixed_encoding?", rb_reg_fixed_encoding_p, 0);
+    rb_define_method(rb_cRegexp, "names", rb_reg_names, 0);
+    rb_define_method(rb_cRegexp, "named_captures", rb_reg_named_captures, 0);
 
     rb_define_const(rb_cRegexp, "IGNORECASE", INT2FIX(ONIG_OPTION_IGNORECASE));
     rb_define_const(rb_cRegexp, "EXTENDED", INT2FIX(ONIG_OPTION_EXTEND));
@@ -2830,6 +2947,8 @@
     rb_undef_method(CLASS_OF(rb_cMatch), "new");
 
     rb_define_method(rb_cMatch, "initialize_copy", match_init_copy, 1);
+    rb_define_method(rb_cMatch, "regexp", match_regexp, 0);
+    rb_define_method(rb_cMatch, "names", match_names, 0);
     rb_define_method(rb_cMatch, "size", match_size, 0);
     rb_define_method(rb_cMatch, "length", match_size, 0);
     rb_define_method(rb_cMatch, "offset", match_offset, 1);
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 14162)
+++ ChangeLog	(revision 14163)
@@ -1,3 +1,12 @@
+Mon Dec 10 06:41:00 2007  Tanaka Akira  <akr@f...>
+
+	* re.c (rb_reg_names): new method Regexp#names.
+	  (rb_reg_named_captures): new method Regexp#named_captures
+	  (match_regexp): new method MatchData#regexp.
+	  (match_names): new method MatchData#names.
+
+	* lib/pp.rb (MatchData#pretty_print): show names of named captures.
+
 Mon Dec 10 01:35:06 2007  Yukihiro Matsumoto  <matz@r...>
 
 	* parse.y (expr): redefinable not (!) operator.
Index: lib/pp.rb
===================================================================
--- lib/pp.rb	(revision 14162)
+++ lib/pp.rb	(revision 14163)
@@ -473,10 +473,24 @@
 
 class MatchData
   def pretty_print(q)
+    nc = []
+    self.regexp.named_captures.each {|name, indexes|
+      indexes.each {|i| nc[i] = name }
+    }
     q.object_group(self) {
       q.breakable
-      q.seplist(1..self.size, lambda { q.breakable }) {|i|
-        q.pp self[i-1]
+      q.seplist(0...self.size, lambda { q.breakable }) {|i|
+        if i == 0
+          q.pp self[i]
+        else
+          if nc[i]
+            q.text nc[i]
+          else
+            q.pp i
+          end
+          q.text ':'
+          q.pp self[i]
+        end
       }
     }
   end
Index: test/ruby/test_regexp.rb
===================================================================
--- test/ruby/test_regexp.rb	(revision 14162)
+++ test/ruby/test_regexp.rb	(revision 14163)
@@ -2,7 +2,9 @@
 
 class TestRegexp < Test::Unit::TestCase
   def test_ruby_dev_24643
-    assert_nothing_raised("[ruby-dev:24643]") { /(?:(?:[a]*[a])?b)*a*$/ =~ "aabaaca" }
+    assert_nothing_raised("[ruby-dev:24643]") {
+      /(?:(?:[a]*[a])?b)*a*$/ =~ "aabaaca"
+    }
   end
 
   def test_ruby_talk_116455
@@ -58,7 +60,8 @@
     assert_equal(8, m.end(:foo))
     assert_equal([5,8], m.offset(:foo))
 
-    assert_equal("aaa [amp] yyy", "aaa &amp; yyy".sub(/&(?<foo>.*?);/, '[\k<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)
@@ -72,9 +75,29 @@
     /(?<id>[A-Za-z_]+)/ =~ "!abc"
     assert_equal("abc", Regexp.last_match(:id))
 
-    /a/ =~ "b"
+    /a/ =~ "b" # doesn't match.
     assert_equal(nil, Regexp.last_match)
     assert_equal(nil, Regexp.last_match(1))
     assert_equal(nil, Regexp.last_match(:foo))
+
+    assert_equal(["foo", "bar"], /(?<foo>.)(?<bar>.)/.names)
+    assert_equal(["foo"], /(?<foo>.)(?<foo>.)/.names)
+    assert_equal([], /(.)(.)/.names)
+
+    assert_equal(["foo", "bar"], /(?<foo>.)(?<bar>.)/.match("ab").names)
+    assert_equal(["foo"], /(?<foo>.)(?<foo>.)/.match("ab").names)
+    assert_equal([], /(.)(.)/.match("ab").names)
+
+    assert_equal({"foo"=>[1], "bar"=>[2]},
+                 /(?<foo>.)(?<bar>.)/.named_captures)
+    assert_equal({"foo"=>[1, 2]},
+                 /(?<foo>.)(?<foo>.)/.named_captures)
+    assert_equal({}, /(.)(.)/.named_captures)
   end
+
+  def test_match_regexp
+    r = /./
+    m = r.match("a")
+    assert_equal(r, m.regexp)
+  end
 end

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

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