/commands/ruby/convert-string-to-integer
ruby convert string to integer: to_i vs Integer()
- 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:
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.rbOutput
"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
| Code | Invalid input | Use for |
|---|---|---|
| str.to_i | Returns 0 (or the leading number) | Lenient parsing where 0 is an acceptable fallback |
| Integer(str) | Raises ArgumentError | Input that must be a valid number: config, CLI options, APIs |
| Integer(str, exception: false) | Returns nil | Validate and fall back: Integer(s, exception: false) || 0 |
| Integer(str, 10) | Raises ArgumentError | Decimal only, so "08" is 8 and not an octal error |
| str.to_i(16) / Integer(str, 16) | As above | Other bases |
| str.to_f / Float(str) | Same pattern | Decimal numbers such as "3.9" |
Pitfalls
- Silent zeros.
params[:page].to_iturns"abc"and""into0, which can pass validation unnoticed. UseInteger(..., exception: false)and check fornil. - nil input.
nil.to_iis0, butInteger(nil)raisesTypeError, and calling another String method onnilraises undefined method for nil. Check fornilfirst when the value may be missing. - Leading zeros.
Integer("08")raises because of octal; pass base 10. - Floats.
Integer("3.9")raises; parse withFloat()and thenround,floororto_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.