48

I'm ashamed to ask this, because it seems like it ought to be obvious, but how does one tell whether a given character in a string is upper or lowercase in Ruby? I see no obvious canned solution in the String class.

I've resorted to the following, which does not consider non-ASCII codes:

def is_lower?(c)
  c >= 'a' && c <= 'z'
end

def is_upper?(c)
  ! is_lower(c)
end

Something else I've considered is:

def is_lower?(c)
    c != c.upcase
end

Is there something more idiomatic for this?

George Armhold
  • 30,824
  • 50
  • 153
  • 232

7 Answers7

60

Use a regex pattern: [A-Z] or:

/[[:upper:]]/.match(c)
sfell77
  • 976
  • 1
  • 9
  • 15
  • This could also be added as a method in `String` with: `class String def upper? !!match(/^[[:upper:]]+$/) end end` (apologies for lack of formatting... comments are limited that way, AFAICT) – lindes May 09 '22 at 18:05
35

I don't think there is something more idiomatic. The only thing you could do -- instead of passing in the string as an argument -- is monkey patch the String class:

class String
  def is_upper?
    self == self.upcase
  end

  def is_lower?
    self == self.downcase
  end
end

"a".is_upper? #=> false
"A".is_upper? #=> true

Using the method in the answer suggested by the commenter above and monkey patching String, you could do this:

class String
  def is_upper?
    !!self.match(/\p{Upper}/)
  end

  def is_lower?
    !!self.match(/\p{Lower}/)
    # or: !self.is_upper?
  end
end
Community
  • 1
  • 1
Mischa
  • 42,876
  • 8
  • 99
  • 111
  • 3
    I'm still shocked that Ruby, which seems to provide a method/hook for everything, does not offer this common method out of the box! – George Armhold Oct 03 '12 at 22:16
  • 3
    @CaffeineComa: Ruby tries very hard to do the right thing. In this particular case, though, it is not obvious what the right thing is, therefore Ruby doesn't do it. For example: what should your two methods return for a character which is neither upper case nor lower case? Or for a character which in some languages is considered upper case and in some languages is considered lower case? – Jörg W Mittag Oct 04 '12 at 01:44
  • Note also `self` is not needed in the second solution, you could simply do `!!match(/\p{Upper})`, but maybe that's not as clear to some. If you are working with ActiveSupport it's also cleaner in my opinion to use `match(/\p{Upper}/).present?` – MusikAnimal Dec 30 '15 at 04:27
  • 1
    I'd recommend using `self != self.downcase` and `self != self.upcase` for `is_upper?` and `is_lower?`, respectively, because `'?'.upcase == '?'` – Piccolo Aug 10 '18 at 21:55
  • @Piccolo: I agree with your identification of the shortcomings of just testing `self == self.upcase`, however I'd argue that the character-class checks (`!!match(/^[[:upper:]]+$/)` or, closer to what's here, `!!match(/^\p{Upper}+$/)`) are better, because they'll deal with a whole lot more such potential pitfalls. – lindes May 09 '22 at 18:12
7

What does it mean for a string to be lower case? Does it mean that the string only contains lower case characters or that it doesn't contain any upper case characters? In my case I want:

"a2".is_lower? #=> true

..which leads me to:

class String

  def is_upper?
    not self.match /[[:lower:]]/
  end

  def is_lower?
    not self.match /[[:upper:]]/
  end

end

Note that /\p{Lower}/ might be better but is unsupported on Ruby 1.8.

  • That "not lower"/"not upper" logic makes much sense for your context; thanks for this. (I'd initially looked at this and overlooked the presence of the `not`, and was finding this flawed, but then I looked closer, and... yeah, this'll do!) – lindes May 09 '22 at 18:16
7

Just use an if statement, e.g. if c == c.upcase or if c == c.downcase.

Laurenz Albe
  • 209,280
  • 17
  • 206
  • 263
Andy Stuart
  • 71
  • 1
  • 1
5

Matching a conversion doesn't emulate the functionality of the libc isupper() and islower() functions in that both should return false for non alpha.

Ranges seem the easiest way to do this for single characters.

class String
  def islower?
    return false if self.size > 1
    ('a'..'z').include? self
  end

  def isupper?
    return false if self.size > 1
    ('A'..'Z').include? self
  end
end
Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
Andrew Smith
  • 91
  • 1
  • 3
4

The easiest way to verify if a character is uppercase or lowercase:

#Can be any character
char = 'a'
if char === char.capitalize then
  return 'Character is uppercase.'
else
  return 'Character is lowercase.'
end

This very simplistic if loop can determine the 'case' of a letter, by checking if it is equal to it's uppercase form. If it's already uppercase, it'll obviously be true.

Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
crownusa
  • 159
  • 1
  • 9
  • if loop ? Why not use a begin switch ? – Martin T. May 22 '14 at 09:48
  • Leaving aside whether this is the easiest way or not, I think it's worth pointing out that isn't necessarily getting the "right answer" -- because it'll treat all non-alphabetic characters as uppercase, when really, they're considered to be something else. – lindes May 09 '22 at 18:21
2

Most of the other solutions here focus on using strings. I use ruby character ordinal values to process only a single character and avoid strings.

def is_lowercase_letter? (x)
  code = x.ord
  97 <= code && code <= 122
end

Uppercase is 65 to 90.

Using 'A'.ord would not rely on you getting the numbers correct and help novice programmers understand what is happening but does not look as clean.

Gerhard
  • 6,850
  • 8
  • 51
  • 81