From 338eb0065bd81ba8ae8b9402abc94804a24594cc Mon Sep 17 00:00:00 2001 From: NAITOH Jun Date: Sat, 13 Jan 2024 06:22:32 +0900 Subject: [PATCH] [ruby/strscan] StringScanner#captures: Return nil not "" for unmached capture (https://github.com/ruby/strscan/pull/72) fix https://github.com/ruby/strscan/issues/70 If there is no substring matching the group (s[3]), the behavior is different. If there is no substring matching the group, the corresponding element (s[3]) should be nil. ``` s = StringScanner.new('foobarbaz') #=> # s.scan /(foo)(bar)(BAZ)?/ #=> "foobar" s[0] #=> "foobar" s[1] #=> "foo" s[2] #=> "bar" s[3] #=> nil s.captures #=> ["foo", "bar", ""] s.captures.compact #=> ["foo", "bar", ""] ``` ``` s = StringScanner.new('foobarbaz') #=> # s.scan /(foo)(bar)(BAZ)?/ #=> "foobar" s[0] #=> "foobar" s[1] #=> "foo" s[2] #=> "bar" s[3] #=> nil s.captures #=> ["foo", "bar", nil] s.captures.compact #=> ["foo", "bar"] ``` https://docs.ruby-lang.org/ja/latest/method/MatchData/i/captures.html ``` /(foo)(bar)(BAZ)?/ =~ "foobarbaz" #=> 0 $~.to_a #=> ["foobar", "foo", "bar", nil] $~.captures #=> ["foo", "bar", nil] $~.captures.compact #=> ["foo", "bar"] ``` * StringScanner#captures is not yet documented. https://docs.ruby-lang.org/ja/latest/class/StringScanner.html https://github.com/ruby/strscan/commit/1fbfdd3c6f --- ext/strscan/strscan.c | 18 +++++++++++------- test/strscan/test_stringscanner.rb | 4 ++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c index a2bf56ce4f..7dbd971ae9 100644 --- a/ext/strscan/strscan.c +++ b/ext/strscan/strscan.c @@ -1243,10 +1243,10 @@ strscan_size(VALUE self) * 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 + * s.scan(/(\w+) (\w+) (\d+) (1980)?/) # -> "Fri Dec 12 " + * s.captures # -> ["Fri", "Dec", "12", nil] + * s.scan(/(\w+) (\w+) (\d+) (1980)?/) # -> nil + * s.captures # -> nil */ static VALUE strscan_captures(VALUE self) @@ -1262,9 +1262,13 @@ strscan_captures(VALUE self) new_ary = rb_ary_new2(num_regs); for (i = 1; i < num_regs; i++) { - VALUE str = extract_range(p, - adjust_register_position(p, p->regs.beg[i]), - adjust_register_position(p, p->regs.end[i])); + VALUE str; + if (p->regs.beg[i] == -1) + str = Qnil; + else + str = extract_range(p, + adjust_register_position(p, p->regs.beg[i]), + adjust_register_position(p, p->regs.end[i])); rb_ary_push(new_ary, str); } diff --git a/test/strscan/test_stringscanner.rb b/test/strscan/test_stringscanner.rb index 2fce4c3e74..29626b159f 100644 --- a/test/strscan/test_stringscanner.rb +++ b/test/strscan/test_stringscanner.rb @@ -737,8 +737,8 @@ module StringScannerTests def test_captures s = create_string_scanner("Timestamp: Fri Dec 12 1975 14:39") s.scan("Timestamp: ") - s.scan(/(\w+) (\w+) (\d+) /) - assert_equal(["Fri", "Dec", "12"], s.captures) + s.scan(/(\w+) (\w+) (\d+) (1980)?/) + assert_equal(["Fri", "Dec", "12", nil], s.captures) s.scan(/(\w+) (\w+) (\d+) /) assert_nil(s.captures) end