How to detect if (number + chars (not number)) - ruby-on-rails

How would I detect if I have this scenario, I would be getting this inputs
3b => allow
4b => allow
55b => allow
1111bbbb => allow
num45 => no !
and if I do allow given, I wold also like to remove all characters that are not numbers
3b => 3
555B => 555
11 => 11
I have tried to check if the given input is numeric or not, but this condition is out of scope of my knowledge.
Thanks for your time and consideration.

You can use:
/\A(\d+)[a-z]*\z/i
If the expression matches your desired number will be in the first capturing group.
Example at Rubular. (It uses ^/$ instead of \A/\z just for the demonstration, you should use \A/\z.)

This will look for integer + string and convert it to an integer. It will ignore a string + integer input.
input = '45num'
if input.match(/\d+[a-zA-Z]+/)
result = input.to_i
end
result => 45

You really want to use: str[/\A\d+/] - This will give you the leading digits or nil.

Hmm I am no regex ninja but I think you could use: ^([\d]+) to capture JUST the number. give it a try here

if the string begins with a number
!/^[0-9]/.match(#variable).nil?
if it does, get only the number part
#variable = #variable.gsub(/[^0-9]/, '')

Related

Ruby Regex for repeated numbers in a string

If i have a string like "123123123" - Here 123 is repeated 3 times.
1. So how can i get only "123" in ruby?
2. So if the string is "12312312" - Here 123 is repeated 2 times and then just 12, so here still i need to get "123".
3. Even if string is 99123123123, still i need to get 123.
Is this possible in Ruby Regex?
EDIT: I want this to solve Project Euler Problem 26 . So here 123 can be anything. All i want is to extract 1 number of at-least 2 repeated numbers.
This regex will detect all repeating groups.
(\d+)(?=.*\1)
Demo
Works great with ruby too.
result = '9912341234123'.scan(/(\d+)(?=.*\1)/)
#gets group with largest length
longestRepeatingGroup = result.max_by{|arr| arr[0].length}
puts longestRepeatingGroup
puts longestRepeatingGroup[0].length
Try this
99123123123.scan(/123/).count
12312312.scan(/123/).count

Where do I put the option to ignore special characters with Regexp.new?

Here is the code:
def autocomplete
if(params[:terms])
key = params[:terms]
customers = Customer.where(:$or => [
{:first_name => Regexp.new(/^#{key}/i)},
{:last_name => Regexp.new(/^#{key}/i)},
{:email => Regexp.new(/^#{key}/i)},
#{:phone => Regexp.new(/^#{key}[d+]/i)},
{:phone => Regexp.new(/^#{key.gsub(/\D+/,'')}/)},
{:zip_code => key.to_i },
{:street1 => Regexp.new(/#{key}/i)},
{:street2 => Regexp.new(/#{key}/i)}
]
)
The gsub method suggested by Tin Man gets me almost there - it strips any non-Digit characters from the search string only when searching in the :phone field in my DB.
The last problem is that the :phone field in the DB might actually have non-Digits in it (and I want to allow users to enter phone numbers however they want), so I need to temporarily ignore dashes when I'm searching (using find() in Mongo)
Not sure if I should do it at this level in the autocomplete function or if I should do it in the autocomplete.js module...
SUMMARY - I want to :phone.gsub(/\D+/,'') but gsub only works on strings, not a reference like this.
Some things I see:
Regexp.new(/^#{key}[d+]/i)}
[\d+] is nonsense. Drop the surrounding [].
For:
{:zip_code => key.to_i },
Don't convert the zipcode to an integer. Some zip codes are hyphenated, which will drop the trailing value. Also, unless you intend to perform math on the value, leave it as a string.
What is $or? Using a global is usually a sign of code-smell. There are few reasons to use one in Ruby, and I've never found a good use for one in my code, and it's something that can usually be refactored out easily using a constant.
I think you actually answered my question by pointing out the key.to_i for ZIP - that's actually exactly what I WANT to do with Phone Number - strip out all the dashes, spaces, brackets, etc. I am going to give that a try.
No, no, no, no. to_i won't do what you want. '0-1'.to_i => 0 and '0.1'.to_i => 0. Instead you want to strip out all non-numeric characters from the string using gsub, then you're done:
'0.1'.gsub(/\D+/, '')
=> "01"
'123-456-7890'.gsub(/\D+/, '')
=> "1234567890"
'(123) 456 7890'.gsub(/\D+/, '')
=> "1234567890"
'0.1'.gsub(/\D+/, '').to_i
=> 1
Note what happened above when to_i received the "01", the leading zero was removed because it wasn't significant for the representation of an Fixnum. You can force it to display using a string format, but why? A phone number is NOT a numeric value, it's a string value, even though it is a bunch of numbers. We NEVER need to do addition on them, or any math, so it's senseless to convert it to an integer. Keep it as a string of digits.

Rails 3 - Compare part of integer with other integer

I'm working for almost 4 weeks with Ruby on Rails now, so consider me as a beginner.
When performing a conditional find query, I need to compare a part of an integer (put in a string..) with another integer.
#invs = Inv.find(:all, :conditions => {:cnr => INTEGER_TO_BE_COMPARED_TO })
Well, I found a way to get a certain part of an integer and wrote the following method:
def get_part_of_int
#r = Integer((#cnr % 10000000)/100000.0)
#r = "%02d" % #r
#r.to_s
end
This should give the output #r = 01 from #cnr = 40138355
The target is to only show invs with e.g. 01 as second and third digit.
I'm using:
Rails 3.2.8
Ruby 1.9.3p194
Thank you all in advance.
== Edit: ==
I realised there is no question mark in my post.. And there is some confusion.
The value of the column name cnr should be stripped to the 2nd and 3rd digit and be compared to a string e.g. 01.
Thank you #Salil for you suggestion.
However this doesn't work.. But I understand the way of using it. The following will convert the string :cnr to :nr.
Inv.find(:all, :conditions => {:cnr.to_s[1,2] => '01' })
Is there a way to compare a part of the value of the column with e.g. 01?
Maybe I should think the other way around. Is it possible to search for cnrs with the 2nd and 3rd digit e.g. 01? The trick is that these numbers are always as 2nd and 3rd digit. I assume a fuzzy search with e.g. Solr doesn't work, because when searching for 01 I don't want the cnr 40594013.
Can this be done in some way?
Thank you in advance and my apologies for confusing you.
if your question is how to get the second and third digit from a integer?
You can use following
40138355.to_s[1,2] ##This will give you "01"
EDITED Ref:- Substring
#invs = Inv.find(:all, :conditions => ["SUBSTRING(cnr,1,2) =?", #cnr.to_s[1,2] ])

Regular expression for valid subdomain in Ruby

I'm attempting to validate a string of user input that will be used as a subdomain. The rules are as follows:
Between 1 and 63 characters in length (I take 63 from the number of characters Google Chrome appears to allow in a subdomain, not sure if it's actually a server directive. If you have better advice on valid max length, I'm interested in hearing it)
May contain a-zA-Z0-9, hyphen, underscore
May not begin or end with a hyphen or underscore
EDIT: From input below, I've added the following:
4. Should not contain consecutive hyphens or underscores.
Examples:
a => valid
0 => valid
- => not valid
_ => not valid
a- => not valid
-a => not valid
a_ => not valid
_a => not valid
aa => valid
aaa => valid
a-a-a => valid
0-a => valid
a&a => not valid
a-_0 => not valid
a--a => not valid
aaa- => not valid
My issue is I'm not sure how to specify with a RegEx that the string is allowed to be only one character, while also specifying that it may not begin or end with a hyphen or underscore.
Thanks!
You can't can have underscores in proper subdomains, but do you need them? After trimming your input, do a simple string length check, then test with this:
/^[a-z\d]+(-[a-z\d]+)*$/i
With the above, you won't get consecutive - characters, e.g. a-bbb-ccc passes and a--d fails.
/^[a-z\d]+([-_][a-z\d]+)*$/i
Will allow non-consecutive underscores as well.
Update: you'll find that, in practice, underscores are disallowed and all subdomains must start with a letter. The solution above does not allow internationalised subdomains (punycode). You're better of using this
/\A([a-z][a-z\d]*(-[a-z\d]+)*|xn--[\-a-z\d]+)\z/i
I'm not familiar with Ruby regex syntax, but I'll assume it's like, say, Perl. Sounds like you want:
/^(?![-_])[-a-z\d_]{1,63}(?<![-_])$/i
Or if Ruby doesn't use the i flag, just replace [-a-z\d_] with [-a-zA-Z\d_].
The reason I'm using [-a-zA-Z\d_] instead of the shorter [-\w] is that, while nearly equivalent, \w will allow special characters such as รค rather than just ASCII-type characters. That behavior can be optionally turned off in most languages, or you can allow it if you like.
Some more information on character classes, quantifiers, and lookarounds
/^([a-z0-9][a-z0-9\-\_]{0,61}[a-z0-9]|[a-z0-9])$/i
I've took it as a challenge to create a regex that should match only strings with non-repeating hyphens or underscores and also check the proper length for you:
/^([a-z0-9]([_\-](?![_\-])|[a-z0-9]){0,61}[a-z0-9]|[a-z0-9])$/i
The middle part uses a lookaround to verify that.
^[a-zA-Z]([-a-zA-Z\d]*[a-zA-Z\d])?$
This simply enforces the standard in an efficient way without backtracking. It does not check the length, but Regex is inefficient at things like that. Just check the string length (1 to 64 chars).
/[^\W\_](.+?)[^\W\_]$/i should work for ya (try our http://rubular.com/ to test out regular expressions)
EDIT: actually, this doesn't check single/double letter/numbers. try /([^\W\_](.+?)[^\W\_])|([a-z0-9]{1,2})/i instead, and tinker with it in rubular until you get exactly what ya want (if this doesn't take care of it already).

Regex - Cost of an Item

What is the regular expression to check a cost has been provided correctly:
Number must be greater than or equal to 0.01
Number must be less than or equal to 99.99
Possible matches are:
9 | 23.3 | 25.69
Not allowed:
| 2.
Of course, the correct way would be to take the provided string, convert it to a number (catching errors if it's not a parseable number) and then compare that with the valid values.
If it has to be a regex, it's of course possible but ugly:
^(?:[1-9][0-9]?(?:\.[0-9]{1,2})?|0?.0[1-9]|0?.[1-9][0-9]?)$
Explanation:
^ # start of string
(?: # either match
[1-9][0-9]? # a number between 1 and 99
(?:\.[0-9]{1,2})? # optionally followed by a decimal point and up to two digits
| # or
0?.0[1-9] # a number between 0.01 and 0.09 (optionally without leading 0)
| # or
0?.[1-9][0-9]? # a number between 0.1 and 0.99
) # end of alternation
$ # end of string
Of course, in most regex dialects, you can use \d in place of [0-9] without a change in meaning, but I think in this case sticking to the longer version helps readability.
In Ruby, assuming your input string never contains a newline:
if subject =~ /^(?:[1-9][0-9]?(?:\.[0-9]{1,2})?|0?.0[1-9]|0?.[1-9][0-9]?)$/
# Successful match
else
# Match attempt failed
end
Since you care about the number of significant digits, another solution would be to first check if the input looks like a number, and if it passes that test, convert it to a float and check if it's in range.
^(\d{1,2}|\d{0,2}\.\d{1,2})$
would match any number (integer or decimal up to two digits after the decimal point) between 0 and 99.99. Then you just need to check whether the number is >= 0.01. The advantage of this approach is that you can easily extend the range of digits allowed before/after the decimal point if the requirements for valid numbers change, and then adjust the value check accordingly.
I am not sure you need to do this using regular expression why dont you just split the string on '|' into an array and check each element in array is greater than 0.01 and less than 99.99
A solution using a regexp would be hard to maintain since it is a very strange and unintuitive way to solve the problem. It would be hard for anyone reading your code (including yourself in a couple of weeks) to understand what the purpose of the check is.
That said, assuming values 0.00 - 99.99 are valid, the regexp could be
^\d{0,2}(\.\d\d?)?$
Assuming 0.01 - 99.99, it's a bit more complicated:
^0{0,2}(\.(0[1-9]|[1-9]\d?))?|\d{0,2}(\.\d\d)?$
And don't get me started on 0.02 - 99.98... :-)
So basically, don't do this. Convert the string to a numerical value and then do a regular interval check.
try
^\d{1,2}(\.\d{1,2})?$
it checks whether there are 1 or 2 digits and optionally if there is a dot it checks if there are 1 or 2 digits after the dot.
as answer to the comments of your question: nothing speaks against checking for the format before sending the request to a server or something else. range checks could be done somewhere else.
It's not the best but works
(0\.01|0\.02|0\.03| ... |99\.98|99\.99)
Since you're in Rails, you might be better served using validates_numericality_of in your model:
validates_numericality_of :cost, :greater_than_or_equal_to => 0.01,
:less_than_or_equal_to => 0.99
To prevent fractional pennies, use this in conjunction with validates_format_of:
validates_format_of :cost, :with => /\A\d*(\.\d{1,2})?\Z/
This leverages the strength of each validation.

Resources