How to know a text is a number?

Dear friends,
I read a text from VCB. Text can be number or combination of numbers and letters. I wish to change it to length if it is number but before it I need to know is it number or not. Can you help me for it?

@distance = text.to_l
"a".to_l
#=> Error: #<ArgumentError: Cannot convert "a" to Length>

so …

begin
  num = text.to_l
rescue ArgumentError => err
  if err.message.start_with?("Cannot convert")
    # do something else with text
  end
else
  @distance = num
end

You can also test strings using a Regexp (a regular expression.)

In order to be convertible to number, the string must start with numeric characters.

In a regular expression:
\A matches at the beginning of the string
\s* matches zero or more whitespace characters
\d+ matches one or more digit characters
… so the expression is:

is_num = /\A\s*\d+/

… and you can test like:

if text !~ is_num
  # The text does not start with digits,
  # do something else with text
else
  @distance = text.to_l
end

But also the String#start_with? method can also take the regular expression as an argument.
But it’s regular expression doesn’t need the \A since the method purposefully tests from the start of the string. So you can also do …

if text.start_with?(/\s*\d+/)
  @distance = text.to_l
else
  # The text does not start with digits,
  # do something else with text
end

If you do not wish to allow preceding spaces, then omit the \s* from the expression.


Your choice.

1 Like

Dear Dan,
If text for example is 12s, this code cause following error.
Error: #<ArgumentError: Cannot convert “12s” to Length>
I can use “num = text.to_f”. It works if text start by number but no different between 12 and 12s. How can I check text end with “s” or not? Let me know if we have a code like this text.end_with?(“S” || “s”)?

That is the reason why Dan included the other lines of the code… itt will handle the ArgumentError that you get.

2 Likes

Yes you can. And you need to start learning how to look up core Ruby methods on your own.

1 Like

e.g

def onUserText (text, view)
  last_char = text.split("").last
  if last_char  == "s" || last_char  == "S"
    @segment = text.to_i
    # you can put similar error handling (begin / rescue) check as above

  else
    #do something else eg. as Dan suggested
    begin
      num = text.to_l
    rescue ArgumentError => err
      if err.message.start_with?("Cannot convert")
        # do something else with text
      end
    else
      @distance = num
    end
  end
#.
#.
end
1 Like
text.end_with?('s','S')

… is far simpler.

2 Likes

Sure! ( I checked the link you have, I just wanted to give an other example…) :slight_smile:

1 Like

Thank you Dezmo, now I know argument error can deleted by codes.

Also following codes solve my problem.

if text.end_with?('s','S') == true
  @num = text.to_i
  #do something
else
  @distance = text.to_f
   # do something else
end

… is frivolous. The if already tests for truthfulness.

2 Likes

Yea. Sure, This methods never raises an exception. Easy!
https://ruby-doc.org/core-2.5.5/String.html#method-i-to_f


Easy?
This will return a normal float. Independent of the current model unit. You have to take care of it in other part of your code.

1 Like

Thank you Dan, You and Dezmo make my codes beautiful.

I do enjoy your posts. Always teach me something interesting. Thank you.

Avoid comparing the error message text. The API contract states what type the error has but not what the text is. This can be rephrased at any point, or possibly translated.

This would treat the text as being in inches. It fails for models using any other units, when the user specifies a unit, for decimals in countries where a comma is used for decimal symbol, and when using fractions. #to_l is the preferred way to parse text input to a length.

2 Likes

Thank you so much. Also I find this problem and first I should be sure text is number then use text.to_l. In this way I don’t need to be worry about system unit.