29

I just started tinkering with Ruby earlier this week and I've run into something that I don't quite know how to code. I'm converting a scanner that was written in Java into Ruby for a class assignment, and I've gotten down to this section:

if (Character.isLetter(lookAhead))
{      
    return id();
}

if (Character.isDigit(lookAhead))
{
    return number();
}

lookAhead is a single character picked out of the string (moving by one space each time it loops through) and these two methods determine if it is a character or a digit, returning the appropriate token type. I haven't been able to figure out a Ruby equivalent to Character.isLetter() and Character.isDigit().

Flip
  • 6,233
  • 7
  • 46
  • 75
Cory Regan
  • 303
  • 1
  • 4
  • 5

3 Answers3

59

Use a regular expression that matches letters & digits:

def letter?(lookAhead)
  lookAhead.match?(/[[:alpha:]]/)
end

def numeric?(lookAhead)
  lookAhead.match?(/[[:digit:]]/)
end

These are called POSIX bracket expressions, and the advantage of them is that unicode characters under the given category will match. For example:

'ñ'.match?(/[A-Za-z]/)     #=> false
'ñ'.match?(/\w/)           #=> false
'ñ'.match?(/[[:alpha:]]/)  #=> true

You can read more in Ruby’s docs for regular expressions.

Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
  • 2
    `lookAhead =~ /[[:alnum:]]/` if you just want to check whether the char is alphanumeric without needing to know which. – DylanReile Mar 07 '18 at 04:07
14

The simplest way would be to use a Regular Expression:

def numeric?(lookAhead)
  lookAhead =~ /[0-9]/
end

def letter?(lookAhead)
  lookAhead =~ /[A-Za-z]/
end
PinnyM
  • 35,165
  • 3
  • 73
  • 81
  • 2
    This is broken: `letter?('Ä') # => false`. – Jörg W Mittag Jan 27 '13 at 20:31
  • 5
    `/[[:digit:]]/` is better than `/[0-9]/` & `/[[:alpha:]]/` is better than `/[A-Za-z]/`. This will match unicode digits/letters. – Andrew Marshall Jan 27 '13 at 20:31
  • @AndrewMarshall: Correct, I wasn't thinking about Unicode. My primary point was that Regex was the way to go, and your answer is the more accurate one for letters. I'm not sure if there exists a Unicode digit however, in which case the answers are identical for digits. – PinnyM Jan 27 '13 at 20:43
  • @PinnyM There are plenty of [non-ASCII digit characters](https://en.wikipedia.org/wiki/Numerals_in_Unicode). – Andrew Marshall Jan 27 '13 at 20:45
  • @AndrewMarshall: Gosh, I never knew about this - thanks for the link! – PinnyM Jan 27 '13 at 20:46
5

Regular expression is an overkill here, it's much more expensive in terms of performance. If you just need a check is character a digit or not there is a simpler way:

def is_digit?(s)
  code = s.ord
  # 48 is ASCII code of 0
  # 57 is ASCII code of 9
  48 <= code && code <= 57
end

is_digit?("2")
=> true

is_digit?("0")
=> true

is_digit?("9")
=> true

is_digit?("/")
=> false

is_digit?("d")
=> false
Alexander
  • 455
  • 6
  • 11
  • 1
    This is good (for ASCII digits), but will also return true for strings that just _start_ with a digit, e.g. `'1 is the loneliest number'.ord => 49`. – David Moles Mar 03 '21 at 20:21