String#include?
String#include? checks whether a substring exists within a string. It returns a boolean value, making it straightforward for conditional logic throughout your Ruby code. This method has been available since Ruby 1.8, making it one of the oldest and most reliable string methods in the language.
Key takeaways
include?is the simplest way to ask whether one text contains another.- It performs case-sensitive character matching.
- Use it for quick checks, file extension tests, and validation rules.
- Convert both sides to the same case when you want case-insensitive matching.
- Reach for a regex if you need a more flexible search than a literal substring.
Signature
string.include?(other_str) -> true or false
| Parameter | Type | Description |
|---|---|---|
other_str | String | The substring to search for |
The method takes a single argument: the substring you want to find. It does not accept a regular expression, so the search is always a literal match. This makes include? predictable and easy to reason about when you need a straightforward yes-or-no answer.
Code Examples
Basic substring check
text = "Hello, World!"
text.include?("Hello") # => true
text.include?("World") # => true
text.include?("Ruby") # => false
The output is a simple boolean, so you can drop include? directly into an if condition or use it as a guard clause. The check is straightforward: either the substring is present somewhere in the text, or it is not.
Case-sensitive matching
email = "user@example.com"
email.include?("example") # => true
email.include?("EXAMPLE") # => false (case matters)
email.include?("@") # => true
This is important to remember: include? performs exact character matching. If you need case-insensitive checking, convert both strings to the same case first. The normalization step is a small but essential detail because Ruby treats uppercase and lowercase characters as completely distinct, even for the same letter.
email.upcase.include?("EXAMPLE") # => true when email is "user@example.com"
Normalizing to the same case before calling include? is the standard approach when the search should be case-insensitive. Calling upcase on the receiver creates a temporary uppercase copy, which is fine for short strings but worth keeping in mind for very large texts where you might want to downcase instead.
Using in conditional statements
filename = "report.pdf"
if filename.include?(".pdf")
puts "Processing PDF file"
# Output: Processing PDF file
end
if filename.include?(".doc")
puts "Processing Word document"
# No output - condition is false
end
This pattern is common for file type detection. You can chain multiple checks for more complex logic, but keep in mind that each include? call scans the entire string from the beginning, so three checks on the same text means three full scans.
Checking for multiple substrings
message = "Please contact support@example.com for help"
message.include?("contact") # => true
message.include?("http") # => false
message.include?("@") # => true
When checking for several substrings at once, the calls read naturally as a series of yes-or-no questions. Each one is independent, so the order does not matter. For a large set of patterns, however, a regular expression with alternation is more efficient than repeated include? calls.
Practical validation example
def valid_username?(username)
return false if username.include?(" ")
return false if username.include?("@")
username.length >= 3
end
valid_username?("john_doe") # => true
valid_username?("john doe") # => false (contains space)
valid_username?("ab") # => false (too short)
Return Value
Returns true if the text contains the given substring anywhere within it, false otherwise. The search is case-sensitive, meaning “A” and “a” are considered different characters. The method stops searching as soon as it finds a match, so performance is proportional to the length of the text being searched.
Edge Cases
Empty string
"".include?("") # => true (empty string is always found)
"hello".include?("") # => true
This behavior follows the mathematical definition where an empty set is a subset of all sets. While technically true, checking for an empty substring is rarely useful in practice. The result makes sense in set theory but is almost never the question a program actually intends to ask.
Nil argument
"hello".include?(nil)
# => NoMethodError: undefined method `include?' for "hello":String
Passing nil raises a NoMethodError because nil does not have a to_s conversion in this context. Always ensure your argument is a string before calling include?. A quick guard like return false if other_str.nil? or other_str.to_s can prevent the error, but be aware that nil.to_s returns an empty string which always matches.
Special characters
"price: $50".include?("$") # => true
"a\tb".include?("\t") # => true (tabs are matched)
"line1\nline2".include?("\n") # => true (newlines are matched)
The method handles all ASCII and Unicode characters correctly, including whitespace, punctuation, and special symbols.
Common mistakes
One common mistake is forgetting that include? is case-sensitive. If you want “Example” and “example” to match, normalize the strings before checking.
Another mistake is using include? for something more complex than a literal substring search. If you need to match optional spacing, punctuation, or character classes, a regular expression will usually be clearer.
Conclusion
String#include? stays useful because it does one thing clearly: it answers whether a string contains another string. Keep the check literal, keep the case rule in mind, and use a regex only when the search needs more flexibility.
Single character vs multi-character
"hello".include?("l") # => true (single character works)
"hello".include?("ll") # => true (multiple characters work)
"hello".include?("lo") # => true (adjacent characters work)
Performance Notes
For very large texts, include? performs a linear search. If you need to check for many different substrings repeatedly, consider using a Set or a Trie data structure instead. For most everyday use cases, the performance is more than adequate.