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
Related
I am trying to write a function in RUBY that will determine if a given string is a valid license plate. A valid license plate has the following format: 3 capital letters, followed by a dash, followed by 4 numbers. EX: HES-2098.
I have written the following function but need some help for pattern matching.
def liscence()
plate = "HES-2098"
plateNo = plate.upcase
if(plate.length == 8)
if(plate == plateNo)
if(/\A-Z\A-Z\A-Z\-\d{4}/.match(plate))
puts "valid"
else
puts "invalid"
end
else
puts "First 3 letter must be uppercase"
end
else
puts "Only 8 char long"
end
end
liscence()
Your regex did not work because \A matches a string start position that can only be one in a string (and you have three). To match an uppercase ASCII letter, you may use a [A-Z] character class.
You can use
if /\A[A-Z]{3}-[0-9]{4}\z/ =~ plate
See the regex and Ruby demos.
Pattern details:
\A - start of string (not line, as with ^) anchor
[A-Z]{3} - exactly 3 (since the limiting quantifier {n} is used) uppercase ASCII letters (from the [A-Z] range in a character class)
- - a literal hyphen (not necessary to escape it outside the character class)
[0-9]{4} - exactly 4 ASCII digits
\z - the very end of the string anchor (not $ that matches the end of the line)
plate[/\A[A-Z]{3}-\d{4}\z/] ? 'valid' : 'invalid'
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/
.....................
I am trying to get a simple Ruby program to run correctly.
I need it to take user input until the user types q for "quit". It also needs to capitalize the last four letters of the users input and, with input under four letters, to capitalize all letters.
It only works for input over four letters, and, when I type "quit", it gets a nil error.
See the code below.
I am using Eclipse with Ruby 2.0.
puts ("\n" * 10)
loop do
puts "Please enter a word. (To quit type q.)" # Gets the users input
puts ("\n" * 3) #Scroll the screen 3 times
str = gets.chomp #Collect the player's response
puts ("\n" * 3) #Scroll the screen 3 times
length = str.length # Counts length of string
str = str[0..(length-5)] + str[(length-4)..length].upcase # Only makes last four letters of user input capitalized
puts str # Shows on screen the user input with capitalized last four letters
puts ("\n" * 3) #Scroll the screen 3 times
break if str == "q"
end
You need to pay attention to [] when you write code like this:
str = str[0..(length-5)] + str[(length-4)..length].upcase
If an index is negative, it is counted from the end of string. For example:
str = "abcde"
str[-1] # => "e"
str[-2] #=> "d"
See String.[] for more details.
With regard to your question, here is my logic:
break if str == "q"
if str.length < 4
str = str.upcase
else
str = str[0...-4] + str[-4..-1].upcase
end
p str
You need to do some checks on your length. If length is less than 4, than length - 5 will return a negative number and your
str[0..(length-5)] + ...
line will be upset. For example. If you type "str", then your code will try to do:
length = 3
str[0..-2] + str[-1..3]
which doesn't make sense. Also, since you check for str == "q" at the end, this is likely also happening for "q". Move your check and break up in the block, and make sure you don't treat all strings as if they're going to be longer than 4 characters.
I have the following logic
def insert_type(type_list, user_input)
case user_input
when user_input == 'library_1'
type_list.slice!('library_' + RegEx for any digit after library_ and stop right there + '__')
type_list << user_input << '__'
when user_input == 'class_A_2'
type_list.slice!('class_' + RegEx for any digit after class_ and stop right there + _A + '__')
type_list << user_input << '__'
end
end
I tried to do the following
[l][i][b][r][a][r][y][_]\d{0,5} #digit from 0 to 99999
It does work, but there should be a more conventional way out there where I could start with l, and ends with the underscore, then add the number since type_list could be:
puts type_list
=> "username_John__userid_58173__userpass_8adsh20__class_A_2__library_0__"
What you want is this:
\w+?(\d{1,5})
Or if you want a specific word, then:
library_(\d{1,5})
It will non-greedily capture the word characters, then add the numerical value to the first capture group.
Basic example: http://regex101.com/r/xE0sM0
Using your output: http://regex101.com/r/aV6yX6 (not sure if you want to match this?)
Explained:
Any word character, including _, non greedy until we find a number
Any number, from 1 to 5 digits (using {0,5} here would actually be 0 to 5 digits)
Wrapping the digit in parentheses () allows the value to be captured.
I have regex as follows:
/^(\d|-|\(|\)|\+|\s){12,}$/
This will allow digits, (, ), space. But I want to ensure string contains atleast 8 digits.
Some allowed strings are as follows:
(1323 ++24)233
24243434 43
++++43435++4554345 434
It should not allow strings like:
((((((1213)))
++++232+++
Use Look ahead within your regex at the start..
/^(?=(.*\d){8,})[\d\(\)\s+-]{8,}$/
---------------
|
|->this would check for 8 or more digits
(?=(.*\d){8,}) is zero width look ahead that checks for 0 to many character (i.e .*) followed by a digit (i.e \d) 8 to many times (i.e.{8,0})
(?=) is called zero width because it doesnt consume the characters..it just checks
To restict it to 14 digits you can do
/^(?=([^\d]*\d){8,14}[^\d]*$)[\d\(\)\s+-]{8,}$/
try it here
Here's a non regular expression solution
numbers = ["(1323 ++24)233", "24243434 43" , "++++43435++4554345 434", "123 456_7"]
numbers.each do |number|
count = 0
number.each_char do |char|
count += 1 if char.to_i.to_s == char
break if count > 7
end
puts "#{count > 7}"
end
No need to mention ^, $, or the "or more" part of {8,}, or {12,}, which is unclear where it comes from.
The following makes the intention transparent.
r = /
(?=(?:.*\d){8}) # First condition: Eight digits
(?!.*[^-\d()+\s]) # Second condition: Characters other than `[-\d()+\s]` should not be included.
/x
resulting in:
"(1323 ++24)233" =~ r #=> 0
"24243434 43" =~ r #=> 0
"++++43435++4554345 434" =~ r #=> 0
"((((((1213)))" =~ r #=> nil
"++++232+++" =~ r #=> nil