From: "zevblut (Zev Blut) via ruby-core" Date: 2026-10-09T05:50:29+00:00 Subject: [ruby-core:127025] [Ruby Bug#22422] MatchData#integer_at returns nil instead of 0 for captures without digits (Possible difference from ticket intention) Issue #22422 has been reported by zevblut (Zev Blut). ---------------------------------------- Bug #22422: MatchData#integer_at returns nil instead of 0 for captures without digits (Possible difference from ticket intention) https://bugs.ruby-lang.org/issues/22422 * Author: zevblut (Zev Blut) * Status: Open * ruby -v: ruby 4.1.0dev (2026-10-07T17:29:37Z master 6203c21e58) +PRISM [arm64-darwin25] * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- The implementation for Feature #21932 differs from what the desired spec says from the comments. I found this while implementing the feature for JRuby. Please confirm if we want to stay with how it is implemented or adjust to the comments. Here are the details: `MatchData#integer_at` returns `nil` for a capture that matched but contains no digits. Feature #21932 says it should behave like `$N&.to_i`, returning `0` there and `nil` only when the group did not match (note 7, with the reasons in note 9). The rdoc also says "`$~.integer_at(N)` is equivalent to `$N&.to_i`". ### Steps to reproduce ```ruby # Compare MatchData#integer_at with $N&.to_i, which Feature #21932 says it is equivalent to. [ ["2024", 10], ["12abc", 10], ["foo", 10], ["", 10], ["T", 10], ["_1", 10], ["0x", 0], ].each do |capture, base| m = /\A(.*)\z/.match(capture) printf "%-8p base %-2d integer_at: %-5p $N&.to_i: %p\n", capture, base, m.integer_at(1, base), m[1]&.to_i(base) end m = /(a)|b/.match("b") printf "%-17s integer_at: %-5p $N&.to_i: %p\n", "unmatched group", m.integer_at(1), m[1]&.to_i ``` ### Actual result ``` ruby 4.1.0dev (2026-10-07T17:29:37Z master 6203c21e58) +PRISM [arm64-darwin25] "2024" base 10 integer_at: 2024 $N&.to_i: 2024 "12abc" base 10 integer_at: 12 $N&.to_i: 12 "foo" base 10 integer_at: nil $N&.to_i: 0 "" base 10 integer_at: nil $N&.to_i: 0 "T" base 10 integer_at: nil $N&.to_i: 0 "_1" base 10 integer_at: nil $N&.to_i: 0 "0x" base 0 integer_at: nil $N&.to_i: 0 unmatched group integer_at: nil $N&.to_i: nil ``` ### Expected result Both columns match: `integer_at` returns `0` for `"foo"`, `""`, `"T"`, `"_1"` and `"0x"`, and `nil` only for the unmatched group. That is the behavior described in [#21932 note 7](https://bugs.ruby-lang.org/issues/21932#note-7) (`"foo"` ��� `0`, `""` ��� `0`). [Note 9](https://bugs.ruby-lang.org/issues/21932#note-9) gives the reason: `nil` is kept to tell an unmatched group apart from a matched `"0"`. ### Cause `match_integer_at` returns the result of `rb_int_parse_cstr` as is ([re.c#L3871-L3873](https://github.com/ruby/ruby/blob/6203c21e58e4c27a91a3336ff2140a9641079025/re.c#L3871-L3873)). That result is `nil` when no digits were parsed. `String#to_i` uses the same parser, but `rb_str_convert_to_inum` turns that `nil` into `0` ([bignum.c#L4343-L4350](https://github.com/ruby/ruby/blob/6203c21e58e4c27a91a3336ff2140a9641079025/bignum.c#L4343-L4350)). The implementation was written before note 7. The current behavior is also recorded in ruby/spec, in `core/matchdata/integer_at_spec.rb` ("returns nil on non-integer matches", `"T"` ��� `nil`). That example would need to change too. `test_match_integer_at` only checks an unmatched group, which is `nil` either way. If `nil` is the intended behavior after all, then the rdoc and #21932 should say so instead. ### Rdoc example Separately, one rdoc example has the wrong result: ```ruby /\d+/.match("011").integer_at(0) #=> 10 in the rdoc, but actually 11 ``` The examples after it (base 12 ��� `13`, base 0 ��� `9`) are correct. --- `integer_at` is new in 4.1, so it is not in the latest stable release (4.0.7). I tested on master at 6203c21e58, and `re.c` is unchanged in today's master (966eaa54c2). JRuby implemented `integer_at` to match CRuby's current behavior (https://github.com/jruby/jruby/pull/9767) and will follow whichever behavior is chosen here. ---Files-------------------------------- integer_at_repro.rb (479 Bytes) -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/