summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2021-09-16 19:50:29 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2021-09-16 19:55:06 +0900
commitf2cb6288bc6f1d5e693841734ce5eb04ff41c2a9 (patch)
tree800cdd8a9ae0217362abc0a88b8c8030ced57f02
parent09d724e6f846b4e53e8571d41ca7d3055d732d9f (diff)
[Feature #18172] Add MatchData#match_length
The method to return the length of the matched substring corresponding to the given argument.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/4851
-rw-r--r--re.c37
-rw-r--r--test/ruby/test_regexp.rb17
2 files changed, 54 insertions, 0 deletions
diff --git a/re.c b/re.c
index 5d5f6fc65c..8e2df1f82c 100644
--- a/re.c
+++ b/re.c
@@ -1335,6 +1335,42 @@ match_nth(VALUE match, VALUE n)
return rb_str_subseq(RMATCH(match)->str, start, end - start);
}
+/*
+ * call-seq:
+ * mtch.match_length(n) -> array
+ *
+ * Returns the length of the captured substring corresponding to the argument.
+ * <em>n</em> can be a string or symbol to reference a named capture.
+ *
+ * m = /(.)(.)(\d+)(\d)(\w)?/.match("THX1138.")
+ * m.match_length(0) #=> 6
+ * m.match_length(4) #=> 1
+ * m.match_length(5) #=> nil
+ *
+ * m = /(?<foo>.)(.)(?<bar>.+)/.match("hoge")
+ * m.match_length(:foo) #=> 1
+ * m.match_length(:bar) #=> 2
+ *
+ */
+
+static VALUE
+match_nth_length(VALUE match, VALUE n)
+{
+ int i = match_backref_number(match, n);
+ struct re_registers *regs = RMATCH_REGS(match);
+
+ match_check(match);
+ backref_number_check(regs, i);
+
+ if (BEG(i) < 0)
+ return Qnil;
+
+ update_char_offset(match);
+ const struct rmatch_offset *const ofs =
+ &RMATCH(match)->rmatch->char_offset[i];
+ return LONG2NUM(ofs->end - ofs->beg);
+}
+
#define MATCH_BUSY FL_USER2
void
@@ -4136,6 +4172,7 @@ Init_Regexp(void)
rb_define_method(rb_cMatch, "begin", match_begin, 1);
rb_define_method(rb_cMatch, "end", match_end, 1);
rb_define_method(rb_cMatch, "match", match_nth, 1);
+ rb_define_method(rb_cMatch, "match_length", match_nth_length, 1);
rb_define_method(rb_cMatch, "to_a", match_to_a, 0);
rb_define_method(rb_cMatch, "[]", match_aref, -1);
rb_define_method(rb_cMatch, "captures", match_captures, 0);
diff --git a/test/ruby/test_regexp.rb b/test/ruby/test_regexp.rb
index 66a60b8d06..b9e64a47e7 100644
--- a/test/ruby/test_regexp.rb
+++ b/test/ruby/test_regexp.rb
@@ -490,6 +490,23 @@ class TestRegexp < Test::Unit::TestCase
assert_equal("oge\u3042", m.match(:bar))
end
+ def test_match_matchsubstring
+ m = /(.)(.)(\d+)(\d)(\w)?/.match("THX1138.")
+ assert_equal(6, m.match_length(0))
+ assert_equal(1, m.match_length(4))
+ assert_nil(m.match_length(5))
+
+ m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
+ assert_equal(1, m.match_length(1))
+ assert_nil(m.match_length(2))
+ assert_equal(1, m.match_length(3))
+
+ m = /(?<foo>.)(?<n>[^aeiou])?(?<bar>.+)/.match("hoge\u3042")
+ assert_equal(1, m.match_length(:foo))
+ assert_nil(m.match_length(:n))
+ assert_equal(4, m.match_length(:bar))
+ end
+
def test_match_inspect
m = /(...)(...)(...)(...)?/.match("foobarbaz")
assert_equal('#<MatchData "foobarbaz" 1:"foo" 2:"bar" 3:"baz" 4:nil>', m.inspect)