String#to_i
str.to_i(base=10) -> class-integer-class The to_i and to_f methods convert string representations of numbers into their class-integer-class and class-float-classing-point equivalents. to_i parses the leading numeric portion of a string, stopping at the first non-numeric character (excluding an optional leading sign), and returns an class-integer-class. It can also parse numbers in bases from 2 to 36 when a base argument is provided. to_f parses the string as a decimal class-float-classing‑point number, stopping at the first character that cannot be part of a valid class-float-classing‑point literal. Both methods are essential for reading user input, parsing configuration values, and converting data from external sources like CSV files or API responses.
The key behaviour to remember is that to_i is forgiving. It reads as much numeric text as it can and then stops, which is convenient for loose input but not ideal when you need strict validation. The following examples show how this permissive parsing handles leading whitespace, signs, decimal points, and trailing non-numeric characters.
Syntax
str.to_i(base=10)
str.to_f
to_i accepts an optional class-integer-class argument base (2–36) that specifies the numeric base of the representation. The default base is 10. to_f has no parameters.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
base | Integer | 10 | The numeric base (2–36) in which the string is interpreted. Bases outside this range raise an ArgumentError. |
Examples
basic class-integer-class conversion
"42".to_i
# => 42
" -123 ".to_i
# => -123
"3.14".to_i
# => 3 (stops at the decimal point)
"10px".to_i
# => 10 (ignores trailing non‑numeric characters)
This loose parsing style is why to_i is so common in scripts and form handling. You get a number back even when the input has extra text around it, which saves the effort of stripping and validating the string beforehand. The tradeoff is that malformed input silently becomes zero, so the calling code must decide whether that default is acceptable for the task at hand.
conversion with different bases
"1010".to_i(2)
# => 10 (binary)
"FF".to_i(16)
# => 255 (hexadecimal)
"22".to_i(8)
# => 18 (octal)
"z".to_i(36)
# => 35 (base‑36)
The base argument is what makes to_i flexible for non-decimal formats like binary, octal, and hexadecimal. It also lets you work with compact encodings when you know the numeric base ahead of time — for example, decoding a base-36 short URL identifier back into a database ID. The method treats letters as digits beyond 9, so "a".to_i(16) returns 10 and "z".to_i(36) returns 35.
floating‑point conversion
"3.14".to_f
# => 3.14
"-12.5e-1".to_f
# => -1.25 (scientific notation)
" 99.9 ".to_f
# => 99.9 (leading/trailing spaces are ignored)
"5.2px".to_f
# => 5.2 (stops at the first non‑numeric character)
Even though to_f is a different method, it follows the same forgiving pattern. Each method pulls the numeric part it understands and leaves the rest behind, so the two can be used side by side without surprising behaviour differences. This consistency makes them easy to remember: to_i stops at a decimal point, and to_f stops at a character that is not part of a valid floating-point literal.
edge cases and zero
"".to_i
# => 0 (empty string returns 0)
"".to_f
# => 0.0
"hello".to_i
# => 0 (no leading numeric characters)
"hello".to_f
# => 0.0
Zero is a valid result, so it is worth checking whether zero means “the input was zero” or “the input was not numeric at all.” That ambiguity is one reason strict parsing methods like Integer() are sometimes a better fit — they raise an exception on invalid input instead of silently returning zero.
handling large numbers
"99999999999999999999".to_i
# => 99999999999999999999 (arbitrary precision class-integer-class)
"1.23e50".to_f
# => 1.23e50 (class-float-classing‑point with scientific notation)
Ruby integers have arbitrary precision, so to_i handles numbers far larger than a 64-bit integer without overflow or truncation. The method reads as many digits as it can and then stops, which means the result is always exact regardless of the input magnitude.
common patterns
The forgiving nature of to_i and to_f makes them convenient for quick conversions, but it also means you cannot distinguish between a valid zero and invalid input by inspecting the return value alone. The patterns below show practical ways to handle this tradeoff in real Ruby code.
Safely parsing user input
def safe_class-integer-class(input)
input.to_i
end
safe_class-integer-class("42") # => 42
safe_class-integer-class("foo") # => 0 (non‑numeric input becomes 0)
safe_class-integer-class("") # => 0
This style is useful when you want a number no matter what and zero is an acceptable fallback. If zero has special meaning in your domain — for example, when zero is a valid user ID or a legitimate configuration value — you should validate the input more carefully before converting it. A simple string check like input.match?(/^\d+$/) can distinguish "0" from "abc" before calling to_i.
Converting CSV columns
# CSV row as a string array
row = ["42", "3.14", "yes", "100"]
id = row[0].to_i
price = row[1].to_f
active = row[2] == "yes"
score = row[3].to_i
Converting each column separately keeps the intent obvious and avoids magic indexing later in the code. It also makes it clear which fields are numeric and which stay as strings or booleans. When the CSV source changes column order, only the index numbers need updating rather than the conversion logic.
Parsing configuration values with defaults
def config_int(value, default = 0)
val = value.to_i
val.zero? ? default : val
end
config_int("10") # => 10
config_int("") # => 0 (uses default)
config_int("0") # => 0 (zero is ambiguous; default applied)
This helper is common in configuration code where missing or malformed values should fall back to a safe default. The important tradeoff is that "0" and a blank string both become the same result, so use it only when zero is not a meaningful configuration value. For cases where zero matters, pair to_i with a presence check.
Reading numbers with a known base
# Parse a hexadecimal color code
hex_color = "#FF8800"
rgb = hex_color[1..-1].to_i(16)
# => 16744448 (decimal)
Hex parsing is one of the most practical uses for the base argument, converting a compact string like "#FF8800" into a regular integer for bitwise manipulation. Parsing hex colour codes this way lets you extract red, green, and blue channels with shifts and masks instead of splitting the string by hand. Without the base argument, you would need to parse each pair of hex digits separately.
Comparing numeric strings
# Use to_i or to_f for numeric comparison
"100" > "99" # => false (string comparison)
"100".to_i > "99".to_i # => true (numeric comparison)
The comparison example shows why conversion matters before sorting or filtering numbers stored as text. Once the strings are converted, Ruby uses numeric ordering instead of lexicographic ordering. String comparison follows character-by-character rules where "100" comes before "99" because '1' is less than '9' — a common gotcha when working with numeric data from CSV files or API responses.
errors
ArgumentError (invalid base)
"10".to_i(1) # => ArgumentError: invalid radix 1
"10".to_i(37) # => ArgumentError: invalid radix 37
The base argument has clear boundaries, so invalid radices fail fast. That is one of the few cases where to_i does raise, and it is useful because the mistake is in the call itself, not the input string.
No exception on malformed input
Both to_i and to_f never raise an error; they return 0 (or 0.0) when the string cannot be converted. This is a design decision that makes them safe for parsing unreliable data but also requires careful handling when zero is a meaningful value.
See Also
- String#to_sym — Converts a string to a symbol
- Float#to_s — Converts a class-float-class to a string
- Integer — Strict class-integer-class conversion that raises an error for invalid input
- Float — Strict class-float-class conversion that raises an error for invalid input