check value starting with decimal ruby on rails - ruby-on-rails

How do I check a value starting with a decimal
is_a_number(value) .... works for 12, 12.0, 12.2, 0.23 but not .23
Basically I'm doing a validation in a form, and I want to allow values starting with . i.e .23
but obviously pop up a flag (false) when its not a number

".23" isn't really a number, in my book.
If you want to treat it like one, check if the first character is a decimal point, if it is, prepend a "0" and try again.
Actually, you could probably prepend a zero regardless. It shouldn't affect the value of any "legitimate" number. (EDIT: As long as you can explicitly specify base 10 when actually converting to a number)

Read your input into a string and dynamically add the zero if needed. For example:
if (inputvar[0] == '.')
inputvar = "0#{inputvar}"
end
The resulting value can be converted into a number by .to_i, .to_f, etc.

Related

Printing a number with either one decimal place or none

Is there a simple way to print a number with either one decimal place or none?
I've searched the net for a method to do that but all of them try to always have a zero after the decimal point..
I want 3.0 to be printed as just 3, and 3.5 to be printed as 3.5.
I tried print('{:.1f}'.format(num)) but this prints 3.0
You have not specified the programming language, so I will provide an answer in pseudocode.
Using if-else
printWithOneOrNoDecimals(n)
if (isNumberInteger(n))
printWithoutDecimals(n)
else
printNumberWithOneDecimal(n)
isNumberInteger(n)
return round(n) == n
The method round(n) should round the number, for example 2.4 to 2. Because 2.4 != 2, isNumberInteger(2.4) would return false and the else statement is exectuted.
Now you can define different formats for printing numbers with or without decimal in printNumberWithOneDecimal and printWithoutDecimals.
Using “right trim” or “right strip”
Another way to achieve the result is to first make the number a string (maybe formatting it to have one decimal) and then “trimming” or “stripping” it from the right, first “all” zeros (in your case at most one) and then the decimal point (if any on the right). Note: trim or strip methods do not give an error if there’s nothing to trim/strip.
I guess that in Python it would be:
'{:.1f}'.format(num).rstrip('0').rstrip('.')
Happy coding, good luck!

How to specify a range in Ruby

I've been looking for a good way to see if a string of items are all numbers, and thought there might be a way of specifying a range from 0 to 9 and seeing if they're included in the string, but all that I've looked up online has really confused me.
def validate_pin(pin)
(pin.length == 4 || pin.length == 6) && pin.count("0-9") == pin.length
end
The code above is someone else's work and I've been trying to identify how it works. It's a pin checker - takes in a set of characters and ensures the string is either 4 or 6 digits and all numbers - but how does the range work?
When I did this problem I tried to use to_a? Integer and a bunch of other things including ranges such as (0..9) and ("0..9) and ("0".."9") to validate a character is an integer. When I saw ("0-9) it confused the heck out of me, and half an hour of googling and youtube has only left me with regex tutorials (which I'm interested in, but currently just trying to get the basics down)
So to sum this up, my goal is to understand a more semantic/concise way to identify if a character is an integer. Whatever is the simplest way. All and any feedback is welcome. I am a new rubyist and trying to get down my fundamentals. Thank You.
Regex really is the right way to do this. It's specifically for testing patterns in strings. This is how you'd test "do all characters in this string fall in the range of characters 0-9?":
pin.match(/\A[0-9]+\z/)
This regex says "Does this string start and end with at least one of the characters 0-9, with nothing else in between?" - the \A and \z are start-of-string and end-of-string matchers, and the [0-9]+ matches any one or more of any character in that range.
You could even do your entire check in one line of regex:
pin.match(/\A([0-9]{4}|[0-9]{6})\z/)
Which says "Does this string consist of the characters 0-9 repeated exactly 4 times, or the characters 0-9, repeated exactly 6 times?"
Ruby's String#count method does something similar to this, though it just counts the number of occurrences of the characters passed, and it uses something similar to regex ranges to allow you to specify character ranges.
The sequence c1-c2 means all characters between c1 and c2.
Thus, it expands the parameter "0-9" into the list of characters "0123456789", and then it tests how many of the characters in the string match that list of characters.
This will work to verify that a certain number of numbers exist in the string, and the length checks let you implicitly test that no other characters exist in the string. However, regexes let you assert that directly, by ensuring that the whole string matches a given pattern, including length constraints.
Count everything non-digit in pin and check if this count is zero:
pin.count("^0-9").zero?
Since you seem to be looking for answers outside regex and since Chris already spelled out how the count method was being implemented in the example above, I'll try to add one more idea for testing whether a string is an Integer or not:
pin.to_i.to_s == pin
What we're doing is converting the string to an integer, converting that result back to a string, and then testing to see if anything changed during the process. If the result is =>true, then you know nothing changed during the conversion to an integer and therefore the string is only an Integer.
EDIT:
The example above only works if the entire string is an Integer and won’t properly deal with leading zeros. If you want to check to make sure each and every character is an Integer then do something like this instead:
pin.prepend(“1”).to_i.to_s(1..-1) == pin
Part of the question seems to be exactly HOW the following portion of code is doing its job:
pin.count("0-9")
This piece of the code is simply returning a count of how many instances of the numbers 0 through 9 exist in the string. That's only one piece of the relevant section of code though. You need to look at the rest of the line to make sense of it:
pin.count("0-9") == pin.length
The first part counts how many instances then the second part compares that to the length of the string. If they are equal (==) then that means every character in the string is an Integer.
Sometimes negation can be used to advantage:
!pin.match?(/\D/) && [4,6].include?(pin.length)
pin.match?(/\D/) returns true if the string contains a character other than a digit (matching /\D/), in which case it it would be negated to false.
One advantage of using negation here is that if the string contains a character other than a digit pin.match?(/\D/) would return true as soon as a non-digit is found, as opposed to methods that examine all the characters in the string.

Discarding everything in a string variable after the second decimal

I have a Ruby string variable with the value 1.14.2.ab3-4.dl0.rhel
However, I want to discard everything after the second decimal so that I get the value as 1.14
I am using the following command:
str.split(".")[0] but it doesn't seem to work
When you split by . on your string you get:
['1', '14', '2', 'ab3-4', 'dl0', 'rhel']
From this you can get the first two items joined by period:
str.split(".")[0..1].join(".")
# or
str.split(".").first(2).join(".")
With a regexp, you could just look for the first number with 2 decimals :
"1.14.2.ab3-4.dl0.rhel"[/\d+\.\d{2}/]
#=> "1.14"
#maxple's answer only works when the substring of interest is at the beginning of the string. As that was not part of the specification (only in the example), I don't think that's a reasonable assumption. (#Eric did not make that assumption.)
There is also ambiguity about your statement, "discard everything after the second decimal". #maxple interpreted that as after the second decimal point (but also discarded the second decimal point), whereas #Eric assumed it meant after the second decimal digit. This is what happens when questions are imprecise.
If the substring is at the beginning of the string, and you mean to discard the second decimal point and everything after, here are two ways to do that.
str = "1.14.2.ab3-4.dl0.rhel"
1. Modify #Eric's regex:
str[/\A\d+\.\d+/]
#=> "1.14"
2. Convert the string to a float and then back to a string:
str.to_f.to_s
#=> "1.14"
#1 returns nil if the desired substring does not exist, whereas #2 returns "0.0". As long as "0.0" is not a valid substring, either can be used to determine if the substring exists, and if it does, return the substring.
You could also use the partition method in String: https://ruby-doc.org/core-2.2.0/String.html#method-i-partition
"1.14.2.ab3-4.dl0.rhel".partition(/\d+\.\d{2}/)[1]
=> "1.14"

Remove first character from Ruby string using [1..n]

I'm trying to basically trying to remove the . in the the string .extension
So I'm using
'.extension'[1..10] #gives extension
Of course this will work for 10 characters, how would I make it work for any length. I dont know what to search for because I dont know what this array style [x..y] is called.
You can use negative indexes. This will offset them from the end. -1 is the last element, -2 is the second last and so on.
'.extension'[1..-1] # => extension

Conditional Regular Expression testing of a CSV

I am doing some client side validation in ASP.NET MVC and I found myself trying to do conditional validation on a set of items (ie, if the checkbox is checked then validate and visa versa). This was problematic, to say the least.
To get around this, I figured that I could "cheat" by having a hidden element that would contain all of the information for each set, thus the idea of a CSV string containing this information.
I already use a custom [HiddenRequired] attribute to validate if the hidden input contains a value, with success, but I thought as I will need to validate each piece of data in the csv, that a regular expression would solve this.
My regular expression work is extremely weak and after a good 2 hours I've almost given up.
This is an example of the csv string:
true,3,24,over,0.5
to explain:
true denotes if I should validate the rest. I need to conditionally switch in the regex using this
3 and 24 are integers and will only ever fall in the range 0-24.
over is a string and will either be over or under
0.5 is a decimal value, of unknown precision.
In the validation, all values should be present and at least of the correct type
Is there someone who can either provide such a regex or at least provide some hints, i'm really stuck!
Try this regex:
#"^(true,([01]?\d|2[0-4]),([01]?\d|2[0-4]),(over|under),\d+\.?\d+|false.*)$"
I'll try to explain it using comments. Feel free to ask if anything is unclear. =)
#"
^ # start of line
(
true, # literal true
([01]?\d # Either 0, 1, or nothing followed by a digit
| # or
2[0-4]), # 20 - 24
([01]?\d|2[0-4]), # again
(over|under), # over or under
\d+\.?\d+ # any number of digits, optional dot, any number of digits
| #... OR ...
false.* # false followed by anything
)
$ # end of line
");
I would probably use a Split(',') and validate elements of the resulting array instead of using a regex. Also you should watch out for the \, case (the comma is part of the value).

Resources