194

I want apple and Apple comparison to be true. Currently

"Apple" == "Apple"  # returns TRUE
"Apple" == "APPLE"  # returns FALSE
Imran Ahmad
  • 2,798
  • 3
  • 28
  • 49
Steven
  • 1,963
  • 2
  • 11
  • 4

5 Answers5

298

You're looking for casecmp. It returns 0 if two strings are equal, case-insensitively.

str1.casecmp(str2) == 0

"Apple".casecmp("APPLE") == 0
#=> true

Alternatively, you can convert both strings to lower case (str.downcase) and compare for equality.

Marc-André Lafortune
  • 78,216
  • 16
  • 166
  • 166
molf
  • 73,644
  • 13
  • 135
  • 118
  • 20
    From my benchmarks casecmp is at least twice as fast as the downcase method – Jacob May 03 '11 at 22:15
  • 85
    `casecmp`: a silly name for a case- *in* -sensitive compare method?! – Zabba Feb 11 '12 at 23:32
  • 4
    @Zabba: Blame the libc people: http://pubs.opengroup.org/onlinepubs/9699919799/functions/strcasecmp.html – mu is too short May 16 '12 at 19:11
  • 17
    If you like using words, you can replace the `== 0` with `zero?` – Andrew Grimm May 16 '12 at 22:23
  • String also has a `.nonzero?` method, so `str1 != str2` can be made case-insensitive as `str1.casecmp(str2).nonzero?` – MrTheWalrus Aug 19 '15 at 15:43
  • 1
    Using #casecmp is better than using #downcase, because the latter doesn't always behave the way a human thinks it should. Eg calling #upcase on the ligature character "ffl" returns the character unchanged. Source: https://mortoray.com/2013/11/27/the-string-type-is-broken/ – Arepo May 09 '17 at 16:27
  • 3
    If you use Rubocop the correct way for it not to complain is `"Apple".casecmp("APPLE").zero?` But personally I like Andres answer below, which uses `.casecmp?` – 8bithero May 29 '17 at 15:31
  • See @andres answer below using .casecmp? for true/false return – Justin Maxwell Aug 22 '17 at 10:11
  • 1
    @AndrewGrimm A caveat to that is if either value is `nil` then the result is `nil` so calling `.zero?` on that will raise an error. So `==` is safer. I'd rather have `"apple".casecmp(b) == 0` than `"apple" .casecmp(b || "").zero?` – mroach May 25 '18 at 08:53
59

In Ruby 2.4.0 you have: casecmp?(other_str) → true, false, or nil

"abcdef".casecmp?("abcde")     #=> false
"aBcDeF".casecmp?("abcdef")    #=> true
"abcdef".casecmp?("abcdefg")   #=> false
"abcdef".casecmp?("ABCDEF")    #=> true

Here you have more info

Andres
  • 11,439
  • 12
  • 48
  • 87
  • 6
    A good improvement to the method but this is one of the least "Ruby sounding" methods I've ever seen. Feels like I'm using Java with this `casecmp` junk. – Joshua Pinter Jan 04 '19 at 22:49
  • 1
    I'd honestly suggest that you use `"aBcDeF".downcase == "abcdef"` instead. Much more readable and the performance gains of using `casecmp` are eliminated in Ruby 2.4+. – Joshua Pinter Jan 04 '19 at 23:14
  • 1
    Wait, what would the difference be between `false` and `nil` for an API like this... – Hakanai Feb 26 '19 at 22:56
  • According to the docs nil is returned when other_str is not a string – ramblex May 31 '19 at 15:12
9

In case you have to compare UTF-8 strings ignoring case:

>> str1 = "Мария"
=> "Мария"
>> str2 = "мария"
=> "мария"
>> str1.casecmp(str2) == 0
=> false
>> require 'active_support/all'
=> true
>> str1.mb_chars.downcase.to_s.casecmp(str2.mb_chars.downcase.to_s) == 0
=> true

It works this way in Ruby 2.3.1 and earlier versions.

For smaller memory footprint you can cherry pick string/multibyte:

require 'active_support'
require 'active_support/core_ext/string/multibyte'

Edit, Ruby 2.4.0:

>> str1.casecmp(str2) == 0
=> false

So casecmp doesn't work in 2.4.0; However in 2.4.0 one can compare UTF-8 strings manually without active_support gem:

>> str1.downcase == str2.downcase
=> true
Adobe
  • 12,967
  • 10
  • 85
  • 126
7

For ruby 2.4 working fine casecmp? for utf-8 strings (mb_chars not needed):

2.4.1 :062 > 'строка1'.casecmp?('СтроКа1')
 => true

but casecmp isn't workin for utf-8:

2.4.1 :062 > 'строка1'.casecmp('СтроКА1')
 => 1
2.4.1 :063 > 'string1'.casecmp('StrInG1')
 => 0
Sergio Belevskij
  • 2,478
  • 25
  • 24
6

casecmp and zero? are ruby inbuilt methods. casecmp returns 0 if two strings are equal, case-insensitively and zero? checks for zero value (==0)

str1.casecmp(str2).zero?
Sivalingam
  • 841
  • 11
  • 16
  • That's what my style checker told me, and I like it because it's clearer than comparing with literal `0`, especially when nested with a more involved condition. – Capt. Crunch May 24 '18 at 08:03
  • as mentioned above, casecmp can return nil which would raise a `NoMethodError` when calling `zero?` – CaTs Jul 02 '21 at 03:01