I'm trying to prompt the user to input a data value, and check that the string they enter only contains the digits 0-9:
class String
def validate(regex)
!self[regex].nil?
end
end
regex = /\A[0-9]\z/
validInput = false
until validInput
puts "Enter digits: "
input = gets.chomp
if !input.validate(regex)
puts "Invalid input. Seeking integer."
else
validInput = true
end
end
However this loop returns false on everything other than single digits excluding 0. I previously had this working with regex = /\A[1-9]\z/, but I going back to where it was working, it doesn't anymore, and this also means the user can't enter 0.
How can I use a regex to validate that user input only contains the digits 0-9?
Add a + quantifier after [1-9](Shouldn't it be [0-9] is you want digits from 0 to 9?). i.e. regex = /\A[0-9]+\z/
You can represent the character class [0-9] as \d so that the regex looks neater: \A\d+\z
The + checks for one(minimum) or more occurrences of a digit in the string. Right now, you are checking for presence of only ONE digit.
s !~ /\D/
.....................
Related
I’m new to ruby, so I want to challenge myself to make a Password Validator, to make the password is valid or not, it needs to match the following conditions
Have at least 7 characters
Have minimum 2 of the following special character('!', '#', '#', '$',
'%', '&', '*')
Have at least 2 number
So I wrote this:
numberOfSymbol=0
numberOfNumbers=0
totalNumber=0
numberArray=(0..9).to_a
inputPassword=gets.chomp
symbol=['!', '#', '#', '$', '%', '&', '*']
neededHash={}
neededHash.default=0
randomGeneratedVar=[]
pppppp=0
symbol.each do |sym|
if inputPassword.include?(sym)
numberOfSymbol+=1
end
end
numberArray.each do |x|
inputPassword.each_char do |y|
if x.to_s == y
neededHash[y] += 1
randomGeneratedVar = neededHash.values
end
end
end
randomGeneratedVar.each {|z| pppppp+=z}
if numberOfSymbol >= 2 && inputPassword.length >= 7 && pppppp >=2
puts "Strong"
else
puts "Weak"
end
After I ran this through the tester it satisfied 16 cases out of 18 cases, I wonder if you guys can help me to perfect this code.
You do not need these amount of variables to create validator.
I think this looks more simple and easy to understand:
def password_validator(password)
symbols = %w(! # # $ % & *)
counter = 0
symbols.each do |element|
if password.include?(element)
counter += 1
end
end
if password.length >= 7 && password.tr("^0-9 ", "").length >= 2 && counter >= 2
"password is valid"
else
"password not valid"
end
end
Symbols is an array of symbols
Walk on each symbol and initializing include?
Just condition if password length >= 7 AND password numbers length >= 2 AND counter of symbols is >= 2
The ruby way and also simple way
def password_complexity
if password.present? && password =~ /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d{2})(?=.*[#$!%*?&]{2})[A-Za-z\d#$!%*?&]{7,}$)/
puts "Strong Password"
else
put "Complexity requirement not met. Please use: 1 uppercase, 1 lowercase, 2 digit and 2 special character, 7 characters"
end
end
If you want you can change regular expression, please find some of the examples
Minimum eight characters, at least one letter and one number:
"^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$"
Minimum eight characters, at least one letter, one number and one special character:
"^(?=.*[A-Za-z])(?=.*\d)(?=.*[#$!%*#?&])[A-Za-z\d#$!%*#?&]{8,}$"
Minimum eight characters, at least one uppercase letter, one lowercase letter and one number:
"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$"
Minimum eight characters, at least one uppercase letter, one lowercase letter, one number and one special character:
"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$!%*?&])[A-Za-z\d#$!%*?&]{8,}$"
Minimum eight and maximum 10 characters, at least one uppercase letter, one lowercase letter, one number and one special character:
"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$!%*?&])[A-Za-z\d#$!%*?&]{8,10}$"
The Rails way
PASSWORD_FORMAT = /\A
(?=.{7,}) # Must contain 8 or more characters
(?=.*\d) # Must contain a digit
(?=.*[a-z]) # Must contain a lower case character
(?=.*[A-Z]) # Must contain an upper case character
(?=.*[[:^alnum:]]) # Must contain a symbol
/x
validates :password,
presence: true,
length: { in: 15 },
format: { with: PASSWORD_FORMAT },
confirmation: true
I have given just example you can modify as per your requirement, Please read this for more information
https://medium.com/#Timothy_Fell/how-to-set-password-requirements-in-rails-d9081926923b
The one exception is that the returned string cannot begin or end with a hyphen, and each odd digit is permitted only a single hyphen before and after each odd digit. For example:
def hyphenate(number)
# code
end
hyphenate(132237847) # should return "1-3-22-3-7-84-7"
"-1-3-22-3-7-84-7-" # incorrect because there is a hyphen before and after
# each beginning and ending odd digit respectively.
"1--3-22-3--7-84-7" # Also incorrect because there is more than one
# single hyphen before and after each odd digit
I suggest to match a non-word boundary \B (that will match a position between two digits) followed or preceded with an odd digit:
number.to_s.gsub(/\B(?=[13579])|\B(?<=[13579])/, '-')
Since the same position can't be matched twice, you avoid the problem of consecutive hyphens.
rubular demo
with the replacement
A simple way is to convert the number to a string, String#split the string on odd digits (using a group so that the odd digit delimiters get into the output), clean up the stray '' strings that String#split will produce, and put it back together with Array#join:
number.to_s.split(/([13579])/).reject(&:empty?).join('-')
def hyphenate(number)
test_string = ''
# Convert the number to a string then iterate over each character
number.to_s.each_char do |n|
# If the number is divisible by 2 then just add it to the string
# else it is an odd number then add it with the hyphens
n.to_i % 2 == 0 ? test_string += n : test_string += "-#{n}-"
end
# Remove the first character of the string if it is a hyphen
test_string = test_string[1..-1] if test_string.start_with?('-')
# Remove the last character of the string if it is a hyphen
test_string = test_string[0..-2] if test_string.end_with?('-')
# Return the string and replace all double hyphens with a single hyphen
test_string.gsub('--', '-')
end
puts hyphenate(132237847)
Returns "1-3-22-3-7-84-7"
Here's another approach for taking a number and returning it in string form with its odd digits surrounded by hyphens:
def hyphenate(number)
result = ""
number.digits.reverse.each do |digit|
result << (digit.odd? ? "-#{digit}-" : digit.to_s)
end
result.gsub("--", "-").gsub(/(^-|-$)/, "")
end
hyphenate(132237847)
# => "1-3-22-3-7-84-7"
Hope it helps!
I'm trying to take the string "xxxyyyzzz" and split it up into an array that groups the same letters. So I want the output to be ["xxx","yyy","zzz"]. I'm not sure why this code keeps on looping. Any suggestions?
def split_up(str)
i = 1
result = []
array = str.split("")
until array == []
if array[i] == array[i-1]
i += 1
else
result << array.shift(i).join("")
end
i = 1
end
result
end
puts split_up("xxxyyyzzz")
The looping is because your until condition never exits. You are incrementing i when the successive characters match, but at the end of the loop you are resetting i to 1.
If you edit this section and add this line:
until array == []
puts i # new line
Then you'll see that i is always 1, and the code keeps printing 1 forever.
Delete the line i = 1 line and you'll get the result you want.
Also, you may be interested in reading about the Ruby string scan method, and pattern matching and capture groups, and using look-ahead and look-behind zero-length assertions, which can match boundaries.
Here is how I would personally accomplish splitting a string at letter boundaries:
"xxxyyyzzz".scan(/(.)(\1*)/).map{|a,b| a+b }
=> ["xxx", "yyy", "zzz"]
The scan method is doing this:
. matches any character e.g. "x", and the parentheses capture this.
\1* matches the previous capture any number of time, e.g. "xx", and the parentheses capture this.
Thus $1 matches the first character "x" and $2 matches all the repeats "xx".
The scan block concatenates the first character and its repeats, so returns "xxx".
As mentioned above, this can be solved using scan like this:
def split_up(string)
repeat_alphabets = /(\w)(\1*)/
string.scan(repeat_alphabets).map do |match|
match[0] << match[1]
end
end
Explanation:
The regular expression matches repeating characters, but due to the construction of the regex matches occur as pairs of the alphabet and remaining repeated instances.
m[0] << m[1] joins the matches to form the required string.
map combines the string into an array and returns the array as it being the last statement.
I have this method where I "spot" user input I want to prevent.
def has_forbidden_prefix?(string)
string =~ %r{^(http://|www.)}
end
If has_forbidden_prefix? is true than I don't want to accept the input.
For example:
Allowed: google.com
Not allowed: www.google.com, http://google.com, http://www.google.com
Now I want to detect also any beginning special characters in my method.
Not allowed: .google.com, /google.com, ...
What do I have to include in my regex?
The regex to see if the first character is an alphanumeric or number is:
^[a-zA-Z0-9]
where ^ stands for the start of the string the regex pattern is applied to. For more info refer to http://www.regular-expressions.info/reference.html
That regex matches what you didn't want from the previous question
So expanding you could have
def has_forbidden_prefix?(string)
disallowed_string = string =~ %r{\A(http://|www)}
non_alphanumeric = string =~ /\A[^a-zA-Z0-9]/
disallowed_string || non_alphanumeric
end
I'm trying to look for a specific character in an array but this character is being entered by the user.
I first order the array and then ask the user to enter a specific character and then I should see if that character exists in any of the words that the array has
For some reason, if when checking for the existence of the character, I "hard code" a character, it works, but it doesn't work if I try to look for the character that the user has entered...
list = [ 'Mom' , 'Dad' , 'Brother' , 'Sister' ]
puts ("Enter the character you would like to find");
character = gets
for i in 0..(list.length - 1)
if (list[i].include?(#{character}))
puts ("Character #{character} found in the word #{list[i]}");
end
Thanks a lot!
It is because gets adds a \n to the end of the string. Use gets.chomp! so you can get rid of the last char.
You should use "chomp" to get rid of the carriage return at the end of the line of the input. In addition you could condense your code as well.
list = [ 'Mom' , 'Dad' , 'Brother' , 'Sister' ]
puts ("Enter the character you would like to find");
character = gets.chomp
list.each do |e|
puts "Character #{character} found in the word #{e}" if e.include?(character)
end