summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--ext/strscan/strscan.c35
-rw-r--r--test/strscan/test_stringscanner.rb11
3 files changed, 50 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index a04f9e67a8..5baff4a096 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Tue May 21 22:47:06 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/strscan/strscan.c (strscan_aref): support named captures.
+ patched by Konstantin Haase [ruby-core:54664] [Feature #8343]
+
Tue May 21 21:48:44 2013 Kouhei Sutou <kou@cozmixng.org>
* test/ruby/test_dir_m17n.rb (TestDir_M17N#test_entries_compose):
diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c
index b81e1f1833..4623994612 100644
--- a/ext/strscan/strscan.c
+++ b/ext/strscan/strscan.c
@@ -38,6 +38,9 @@ struct strscanner
/* the regexp register; legal only when MATCHED_P(s) */
struct re_registers regs;
+
+ /* regexp used for last scan */
+ VALUE regex;
};
#define MATCHED_P(s) ((s)->flags & FLAG_MATCHED)
@@ -456,6 +459,8 @@ strscan_do_scan(VALUE self, VALUE regex, int succptr, int getstr, int headonly)
if (S_RESTLEN(p) < 0) {
return Qnil;
}
+
+ p->regex = regex;
re = rb_reg_prepare_re(regex, p->str);
tmpreg = re != RREGEXP(regex)->ptr;
if (!tmpreg) RREGEXP(regex)->usecnt++;
@@ -983,17 +988,45 @@ strscan_matched_size(VALUE self)
* s[3] # -> "12"
* s.post_match # -> "1975 14:39"
* s.pre_match # -> ""
+ *
+ * s.reset
+ * s.scan(/(?<wday>\w+) (?<month>\w+) (?<day>\d+) /) # -> "Fri Dec 12 "
+ * s[0] # -> "Fri Dec 12 "
+ * s[1] # -> "Fri"
+ * s[2] # -> "Dec"
+ * s[3] # -> "12"
+ * s[:wday] # -> "Fri"
+ * s[:month] # -> "Dec"
+ * s[:day] # -> "12"
+ * s.post_match # -> "1975 14:39"
+ * s.pre_match # -> ""
*/
static VALUE
strscan_aref(VALUE self, VALUE idx)
{
+ const char *name, *name_end;
struct strscanner *p;
long i;
GET_SCANNER(self, p);
if (! MATCHED_P(p)) return Qnil;
- i = NUM2LONG(idx);
+ switch (TYPE(idx)) {
+ case T_SYMBOL:
+ name = rb_id2name(SYM2ID(idx));
+ goto name_to_backref;
+ break;
+ case T_STRING:
+ name = StringValuePtr(idx);
+ name_to_backref:
+ name_end = name + strlen(name);
+ i = onig_name_to_backref_number(RREGEXP(p->regex)->ptr,
+ (const unsigned char* )name, (const unsigned char* )name_end, &(p->regs));
+ break;
+ default:
+ i = NUM2LONG(idx);
+ }
+
if (i < 0)
i += p->regs.num_regs;
if (i < 0) return Qnil;
diff --git a/test/strscan/test_stringscanner.rb b/test/strscan/test_stringscanner.rb
index 2c4cf90828..7f2e5c1ccd 100644
--- a/test/strscan/test_stringscanner.rb
+++ b/test/strscan/test_stringscanner.rb
@@ -457,6 +457,17 @@ class TestStringScanner < Test::Unit::TestCase
assert_equal true, s[2].tainted?
assert_equal true, s[3].tainted?
assert_equal true, s[4].tainted?
+
+ s = StringScanner.new("foo bar")
+ s.scan /(?<a>(\w+)) (?<b>(\w+))/
+ assert_equal 'foo', s[1]
+ assert_equal 'bar', s[2]
+ assert_equal 'foo', s[:a]
+ assert_equal 'bar', s[:b]
+ assert_equal nil, s[:c]
+ assert_equal 'foo', s['a']
+ assert_equal 'bar', s['b']
+ assert_equal nil, s['c']
end
def test_pre_match