rubyguides

String#succ

Signature

str.succ   -> new_string
str.succ!  -> self
str.next   -> new_string
str.next!  -> self

#succ returns a new string. #succ! mutates self in place. #next and #next! are aliases that call the identical C implementation.

Numeric Increment

Digits increment with carry propagation. When 9 rolls over, it increments the digit to its left. If all digits carry, a new digit is prepended.

'0'.succ        # => "1"
'8'.succ        # => "9"
'9'.succ        # => "10"
'00'.succ       # => "01"
'09'.succ       # => "10"
'99'.succ       # => "100"
'1999zzz'.succ  # => "2000aaa"
'0099'.succ     # => "0100"

Lowercase Letters

Lowercase letters follow the same carry logic, preserving case.

'a'.succ        # => "b"
'x'.succ        # => "y"
'z'.succ        # => "aa"
'aa'.succ       # => "ab"
'az'.succ       # => "ba"
'zz'.succ       # => "aaa"

'z' rolls over to 'aa', not to an uppercase letter.

Uppercase Letters

Same behavior as lowercase, but preserves uppercase.

'A'.succ        # => "B"
'Z'.succ        # => "AA"
'AA'.succ       # => "AB"
'AZ'.succ       # => "BA"
'ZZ'.succ       # => "AAA"

Non-Alphanumeric Characters

Non-alphanumerics use the underlying character set’s collating sequence. For ASCII/BINARY encodings, this is byte value order. Non-alphanumerics do not trigger carry propagation — only the rightmost character is ever incremented.

'***'.succ           # => "**+"
'<<koala>>'.succ     # => "<<koalb>>"

* (ASCII 42) increments to + (ASCII 43).

Multibyte Characters

With multibyte encodings like UTF-8, each character is treated as a codepoint. The increment follows the encoding’s collating sequence.

'å'.succ        # => "å" (no next codepoint, wraps to same — depends on encoding)

Behavior varies by Ruby version and encoding. For encodings with no defined successor (or where the last codepoint rolls over), the result may be the same character or require explicit handling.

Mixed Alphanumeric Strings

Carry propagates across and between types. Letters roll over independently of digits.

'THX1138'.succ   # => "THX1139"
'zz99zz99'.succ  # => "aaa00aa00"
'99zz99zz'.succ  # => "100aa00aa"
'ZZZ9999'.succ   # => "AAAA0000"

'ZZZ9999'.succ produces 'AAAA0000' — every character type rolls over independently.

Empty Strings

Returns a new empty string.

''.succ  # => ""

Binary Strings

Each byte is treated as an independent numeric value. A full-byte carry prepends \x01.

"\x00\x00\x00".succ       # => "\x00\x00\x01"
"\xFF\xFF\xFF".succ       # => "\x01\x00\x00\x00"  (ASCII-8BIT encoding)

Frozen Strings

#succ returns a new string and is safe to use on frozen strings. #succ! raises FrozenError on frozen strings in Ruby 3.0+.

s = 'hello'.freeze
s.succ   # => "hellp"     # safe, returns new string

s.succ!  # => FrozenError (Ruby 3.0+)

Gotchas

No numeric awareness. Successor is purely character-based.

'1.0'.succ   # => "1.1", not "2.0"

Mixed-type carry cascades can surprise you. 'ZZZ9999'.succ produces 'AAAA0000' — every character type rolls over independently.

#next conflicts with the next keyword. Inside blocks using next for flow control, prefer #succ to avoid ambiguity.

Non-ASCII encodings follow the encoding’s collating sequence, which may not match locale expectations.

#pred does not exist for strings. Ruby has Integer#pred but not String#pred. There is no built-in way to get the lexicographic predecessor of a string.

See Also

  • String#hex — converts a hex string to an integer
  • String#oct — converts an octal string to an integer