Skip to content

/commands/ruby/convert-string-to-integer

ruby convert string to integer: to_i vs Integer()

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated
tool
Ruby
versions
Ruby 2.6+ (exception: false), Ruby 3.4
os
any

"42".to_i converts a string to an integer, but it never fails: it reads the leading digits and ignores the rest, so "42abc".to_i is 42 and "abc".to_i is 0. When invalid input must be rejected, use Integer("42"), which raises ArgumentError for anything that is not a complete number, or Integer(str, exception: false) to get nil instead.

Compare to_i and Integer()

The example runs CRuby 3.4 compiled to WebAssembly (ruby.wasm, the official Ruby project build) with Node.js:

bash
npm init -y >/dev/null
npm install --silent --no-audit --no-fund @ruby/3.4-wasm-wasi@2.8.1 @ruby/wasm-wasi@2.8.1 >/dev/null 2>&1
cat > ruby.mjs <<'EOF'
import fs from "node:fs/promises";
import { DefaultRubyVM } from "@ruby/wasm-wasi/dist/node";
const wasm = await WebAssembly.compile(await fs.readFile("node_modules/@ruby/3.4-wasm-wasi/dist/ruby+stdlib.wasm"));
const { vm } = await DefaultRubyVM(wasm);
vm.eval(await fs.readFile(process.argv[2], "utf8") + "\n$stdout.flush");
EOF
cat > convert.rb <<'EOF'
inputs = ["42", " 42 ", "-7", "42abc", "abc", "", "3.9", "1_000", "0x1A", "08"]
inputs.each do |s|
  strict = begin
    Integer(s).inspect
  rescue ArgumentError => e
    "#{e.class}: #{e.message}"
  end
  puts "#{s.inspect.ljust(8)} to_i=#{s.to_i.to_s.ljust(4)} Integer()=#{strict}"
end
p Integer("abc", exception: false)
p Integer("08", 10)
p "ff".to_i(16)
p nil.to_i
begin
  Integer(nil)
rescue TypeError => e
  puts "#{e.class}: #{e.message}"
end
EOF
node --no-warnings ruby.mjs convert.rb

Output

"42"     to_i=42   Integer()=42
" 42 "   to_i=42   Integer()=42
"-7"     to_i=-7   Integer()=-7
"42abc"  to_i=42   Integer()=ArgumentError: invalid value for Integer(): "42abc"
"abc"    to_i=0    Integer()=ArgumentError: invalid value for Integer(): "abc"
""       to_i=0    Integer()=ArgumentError: invalid value for Integer(): ""
"3.9"    to_i=3    Integer()=ArgumentError: invalid value for Integer(): "3.9"
"1_000"  to_i=1000 Integer()=1000
"0x1A"   to_i=0    Integer()=26
"08"     to_i=8    Integer()=ArgumentError: invalid value for Integer(): "08"
nil
8
255
0
TypeError: can't convert nil into Integer

to_i stops at the first character that is not a digit (an underscore between digits is allowed), so "3.9" becomes 3, and it ignores leading whitespace. Integer() accepts surrounding whitespace, underscores and prefixes such as 0x, 0b and 0 (octal), but rejects any trailing garbage.

Which one to use

CodeInvalid inputUse for
str.to_iReturns 0 (or the leading number)Lenient parsing where 0 is an acceptable fallback
Integer(str)Raises ArgumentErrorInput that must be a valid number: config, CLI options, APIs
Integer(str, exception: false)Returns nilValidate and fall back: Integer(s, exception: false) || 0
Integer(str, 10)Raises ArgumentErrorDecimal only, so "08" is 8 and not an octal error
str.to_i(16) / Integer(str, 16)As aboveOther bases
str.to_f / Float(str)Same patternDecimal numbers such as "3.9"

Pitfalls

  • Silent zeros. params[:page].to_i turns "abc" and "" into 0, which can pass validation unnoticed. Use Integer(..., exception: false) and check for nil.
  • nil input. nil.to_i is 0, but Integer(nil) raises TypeError, and calling another String method on nil raises undefined method for nil. Check for nil first when the value may be missing.
  • Leading zeros. Integer("08") raises because of octal; pass base 10.
  • Floats. Integer("3.9") raises; parse with Float() and then round, floor or to_i (which truncates), see rounding floats.

Confirm it worked

Test the inputs your program really receives, including an empty string, spaces and a value with letters, and check that each one gives the integer, the nil or the exception you expect.

FAQ

Why does "abc".to_i return 0?

to_i never raises. It reads as many leading digits as it can and returns 0 when there are none. Use Integer("abc") when invalid input must be detected; it raises ArgumentError.

How do I get nil instead of an exception for invalid input?

Pass exception: false (Ruby 2.6+): Integer("abc", exception: false) returns nil, so Integer(input, exception: false) || default gives a fallback value.

Why does Integer("08") raise an error?

A leading 0 means octal for Integer(), and 8 is not an octal digit. Pass the base explicitly, Integer("08", 10), when strings may have leading zeros.

Sources