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

ruby-changes:48812

From: nobu <ko1@a...>
Date: Wed, 29 Nov 2017 16:57:53 +0900 (JST)
Subject: [ruby-changes:48812] nobu:r60929 (trunk): strscan.c: add MatchData-like methods

nobu	2017-11-29 16:57:48 +0900 (Wed, 29 Nov 2017)

  New Revision: 60929

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=60929

  Log:
    strscan.c: add MatchData-like methods
    
    * ext/strscan/strscan.c: added `size`, `captures` and `values_at`
      to StringScanner, shorthands of accessing the matched data.
      based on the patch by apeiros (Stefan Rusterholz) at
      [ruby-core:20412].  [Feature #836]

  Modified files:
    trunk/NEWS
    trunk/ext/strscan/strscan.c
    trunk/test/strscan/test_stringscanner.rb
Index: NEWS
===================================================================
--- NEWS	(revision 60928)
+++ NEWS	(revision 60929)
@@ -216,6 +216,9 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L216
 * StringIO
   * StringIO#write accepts multiple arguments
 
+* StringScanner
+  * Add StringScanner#size, StringScanner#captures, StringScanner#values_at  [Feature #836]
+
 * WEBrick
 
   * Add Server Name Indication (SNI) support [Feature #13729]
Index: ext/strscan/strscan.c
===================================================================
--- ext/strscan/strscan.c	(revision 60928)
+++ ext/strscan/strscan.c	(revision 60929)
@@ -1053,6 +1053,92 @@ strscan_aref(VALUE self, VALUE idx) https://github.com/ruby/ruby/blob/trunk/ext/strscan/strscan.c#L1053
 }
 
 /*
+ * call-seq: size
+ *
+ * Return the amount of subgroups in the most recent match.
+ * The full match counts as a subgroup.
+ *
+ *   s = StringScanner.new("Fri Dec 12 1975 14:39")
+ *   s.scan(/(\w+) (\w+) (\d+) /)       # -> "Fri Dec 12 "
+ *   s.size                             # -> 4
+ */
+static VALUE
+strscan_size(VALUE self)
+{
+    struct strscanner *p;
+
+    GET_SCANNER(self, p);
+    if (! MATCHED_P(p))        return Qnil;
+    return INT2FIX(p->regs.num_regs);
+}
+
+/*
+ * call-seq: captures
+ *
+ * Returns the subgroups in the most recent match (not including the full match).
+ * If nothing was priorly matched, it returns nil.
+ *
+ *   s = StringScanner.new("Fri Dec 12 1975 14:39")
+ *   s.scan(/(\w+) (\w+) (\d+) /)       # -> "Fri Dec 12 "
+ *   s.captures                         # -> ["Fri", "Dec", "12"]
+ *   s.scan(/(\w+) (\w+) (\d+) /)       # -> nil
+ *   s.captures                         # -> nil
+ */
+static VALUE
+strscan_captures(VALUE self)
+{
+    struct strscanner *p;
+    int   i, num_regs;
+    VALUE new_ary;
+
+    GET_SCANNER(self, p);
+    if (! MATCHED_P(p))        return Qnil;
+
+    num_regs = p->regs.num_regs;
+    new_ary  = rb_ary_new2(num_regs);
+
+    for (i = 1; i < num_regs; i++) {
+        VALUE str = extract_range(p, p->prev + p->regs.beg[i],
+                                     p->prev + p->regs.end[i]);
+        rb_ary_push(new_ary, str);
+    }
+
+    return new_ary;
+}
+
+/*
+ *  call-seq:
+ *     scanner.values_at( i1, i2, ... iN )   -> an_array
+ *
+ * Returns the subgroups in the most recent match at the given indices.
+ * If nothing was priorly matched, it returns nil.
+ *
+ *   s = StringScanner.new("Fri Dec 12 1975 14:39")
+ *   s.scan(/(\w+) (\w+) (\d+) /)       # -> "Fri Dec 12 "
+ *   s.values_at 0, -1, 5, 2            # -> ["Fri Dec 12 ", "12", nil, "Dec"]
+ *   s.scan(/(\w+) (\w+) (\d+) /)       # -> nil
+ *   s.values_at 0, -1, 5, 2            # -> nil
+ */
+
+static VALUE
+strscan_values_at(int argc, VALUE *argv, VALUE self)
+{
+    struct strscanner *p;
+    long i;
+    VALUE new_ary;
+
+    GET_SCANNER(self, p);
+    if (! MATCHED_P(p))        return Qnil;
+
+    new_ary = rb_ary_new2(argc);
+    for (i = 0; i<argc; i++) {
+        rb_ary_push(new_ary, strscan_aref(self, argv[i]));
+    }
+
+    return new_ary;
+}
+
+/*
  * Return the <i><b>pre</b>-match</i> (in the regular expression sense) of the last scan.
  *
  *   s = StringScanner.new('test string')
@@ -1392,6 +1478,9 @@ Init_strscan(void) https://github.com/ruby/ruby/blob/trunk/ext/strscan/strscan.c#L1478
     rb_define_method(StringScanner, "[]",          strscan_aref,        1);
     rb_define_method(StringScanner, "pre_match",   strscan_pre_match,   0);
     rb_define_method(StringScanner, "post_match",  strscan_post_match,  0);
+    rb_define_method(StringScanner, "size",        strscan_size,        0);
+    rb_define_method(StringScanner, "captures",    strscan_captures,    0);
+    rb_define_method(StringScanner, "values_at",   strscan_values_at,  -1);
 
     rb_define_method(StringScanner, "rest",        strscan_rest,        0);
     rb_define_method(StringScanner, "rest_size",   strscan_rest_size,   0);
Index: test/strscan/test_stringscanner.rb
===================================================================
--- test/strscan/test_stringscanner.rb	(revision 60928)
+++ test/strscan/test_stringscanner.rb	(revision 60929)
@@ -728,4 +728,26 @@ class TestStringScanner < Test::Unit::Te https://github.com/ruby/ruby/blob/trunk/test/strscan/test_stringscanner.rb#L728
     assert_nil(s[:c])
     assert_nil(s["c"])
   end
+
+  def test_size
+    s = StringScanner.new("Fri Dec 12 1975 14:39")
+    s.scan(/(\w+) (\w+) (\d+) /)
+    assert_equal(4, s.size)
+  end
+
+  def test_captures
+    s = StringScanner.new("Fri Dec 12 1975 14:39")
+    s.scan(/(\w+) (\w+) (\d+) /)
+    assert_equal(["Fri", "Dec", "12"], s.captures)
+    s.scan(/(\w+) (\w+) (\d+) /)
+    assert_nil(s.captures)
+  end
+
+  def test_values_at
+    s = StringScanner.new("Fri Dec 12 1975 14:39")
+    s.scan(/(\w+) (\w+) (\d+) /)
+    assert_equal(["Fri Dec 12 ", "12", nil, "Dec"], s.values_at(0, -1, 5, 2))
+    s.scan(/(\w+) (\w+) (\d+) /)
+    assert_nil(s.values_at(0, -1, 5, 2))
+  end
 end

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

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