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.
Related
I'm new at this and have been practicing on codewars- one of the challenges is a caesar cypher challenge and I've got it pretty much solved except for this one issue...
Here's the code I wrote:
def rot13(string)
alpha = "abcdefghijklmnopqrstuvwxyz"
arr = []
string.each_char.with_index do |char, i|
n = alpha.index(char.downcase)
a = (n.to_i + 13) % 26
unless alpha.include?(char.downcase)
arr << char
end
if char == char.upcase
arr << alpha[a].upcase
else
arr << alpha[a]
end
end
return arr.join
end
puts rot13('10+2 is twelve')
and when I run my code it comes back as this-
1N0N+N2N Nvf Ngjryir
Why are the Ns showing up? Anyone know?
The issue is that you're not checking for non-alphabetical characters properly. Going through the logic:
At line 5, you set n to the index of the character in your alphabet string alpha. Because only letters are included, this call to #include? returns nil for all characters that aren't letters (e.g. your string's first character, '1').
At line 6, you set a to n.to_i + 13. Because nil.to_i is zero, this will always be 13 for any character that isn't a letter.
In the block in lines 7-9, you push char to your array because it doesn't exist in alpha (and so you get '1' as the first character of your output).
But then, in line 10, you push alpha[a].upcase as well if char == char.upcase. If char isn't a letter (e.g. initially '1'), it passes this test (because '1' == '1'.upcase) and your code pushes alpha[13].upcase to the output as well, and 'N' is the 13th letter of the alphabet.
Basically, your checks aren't sufficient. You need to account for numbers and other non-alphabetical characters properly each time.
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
I have a coding problem I solved and want to refactor. I know there has to be a cleaner way of doing what I did.
The goal is to write a method that takes a string of "!" and "?" and reduces the string by eliminating all odd groupings of each symbol.
Example - a string "????!!!" would have an odd grouping of "!!!" because there are three in a row. These would be deleted from the string.
If there is only one "!" or "?" its left because it is not in a group.
Ex -
remove("!????!!!?") answer == "!"
# => ("!????!!!?" --> "!?????" --> "!")
In the first string, the only odd grouping is "!!!", once removed, it leaves a new string with an odd grouping "?????". You remove the next odd grouping so you're left with "!". This fits the desired output.
Another example
remove("!???!!") == ""
# => ("!???!!" --> "!!!" --> "")
Current code:
def remove(s)
arr = [s]
i = 0
until i == arr[0].length
s = s.chars.chunk{|c|c}.map{ |n,a| a.join }.select{|x| x if x.length.even? || x.length <= 1}.join
arr << s
i += 1
end
return arr[-1]
end
My code solves this problem and all test cases. I have a suspicion that my until loop can be removed/refactored so that I could solve this problem in one line and have spent hours trying to figure it out with no luck.
Suppose
str = "???!!!???!"
If we first remove the two groups "???" we are left with "!!!!", which cannot be reduced further.
If we first remove the group "!!!" we are left with "??????!", which cannot be reduced further.
If we are permitted to remove all odd groups of either character without reference to the effect that either has on the other, we obtain !, which cannot be reduced further.
It's not clear what rule is to be used. Here are three possibilities and code to implement each.
I will use the following two regular expressions, and in the first two cases a helper method.
Rq = /
(?<!\?) # do not match a question mark, negative lookbehind
\? # match a question mark
(\?{2})+ # match two question marks one or more times
(?!\?) # do not match a question mark, negative lookahead
/x # free-spacing regex definition mode
which is commonly written /(?<!\?)\?(\?{2})+(?!\?)/.
Similarly,
Rx = /(?<!!)!(!{2})+(?!!)/
def sequential(str, first_regex, second_regex)
s = str.dup
loop do
size = s.size
s = s.gsub(first_regex,'').gsub(second_regex,'')
return s if s.size == size
end
end
I apply each of the three methods below to two example strings:
str1 = "???!!!???!"
str2 = 50.times.map { ['?', '!'].sample }.join
#=> "?!!!?!!!?!??????!!!?!!??!!???!?!????!?!!!?!?!???!?"
Replace all odd groups of "?" then odd groups of "!" then repeat until no further removals are possible
def question_before_exclamation(str)
sequential(str, Rq, Rx)
end
question_before_exclamation str1 #=> "!!!!"
question_before_exclamation str2 #=> "??!??!?!!?!?!!?"
Replace all odd groups of "!" then odd groups of "?" then repeat until no further removals are possible
def exclamation_before_question(str)
sequential(str, Rx, Rq)
end
exclamation_before_question str1 #=> "??????!"
exclamation_before_question str2 #=> "??!????!!?!?!!?!?!!?"
Replace all odd groups of both "?" and "!" then repeat until no further removals are possible
Rqx = /#{Rq}|#{Rx}/
#=> /(?-mix:(?<!\?)\?(\?{2})+(?!\?))|(?-mix:(?<!!)!(!{2})+(?!!))/
def question_and_explanation(str)
s = str.dup
loop do
size = s.size
s = s.gsub(Rqx,'')
return s if s.size == size
end
end
question_and_explanation str1 #=> "!"
question_and_explanation str2 #=> "??!?!!?!?!!?!?!!?"
I don't know the exact Ruby syntax for this, but you could simplify your solution by using regular expressions:
Gather all matches of consecutive characters
if all matches are of even length or 1 exit
Test if matches are an odd length
if an odd length, replace with the empty string
else do nothing
Goto step 1
A solution in Perl would be:
#!perl
use strict;
use warnings;
use feature qw(say);
my $string = '!????!!!?';
sub reduce {
my ($s) = #_;
while ( my #matches = $s =~ m/((.)\2+)/g ) {
last if ! grep { length($_) > 1 && length($_) % 2 == 1 } #matches;
foreach my $match ( #matches ) {
$s =~ s/\Q$match// if length($match) > 1 && length($match) % 2 == 1;
}
}
return $s;
}
say reduce($string);
I could be wrong (this is ruby, after all) but I don't think you'll find a one-liner for this because ruby's utility functions generally aren't recursive. But you can use regex to simplify your logic, at the very least:
def remove(s)
while s =~ /(?<!\!)\!([\!]{2})+(?!\!)/ || s =~ /(?<!\?)\?([\?]{2})+(?!\?)/
s.gsub! /(?<!\!)\!([\!]{2})+(?!\!)/, "" # remove odd !
s.gsub! /(?<!\?)\?([\?]{2})+(?!\?)/, "" # remove odd ?
end
return s
end
To make the regex less mind-boggling, it helps to look at them with 'a' instead of '?' and '!':
/(?<!a)a([a]{2})+(?!a)/ #regex for 'a'
(?<!a) #negative lookbehind: the match cannot start with an 'a'
a([a]{2})+ #the match should be an 'a' followed by 1 or more pairs
(?!a) #negative lookahead: the match cannot end with an 'a'
It should be simple enough with a regular expression replacement
def remove(string)
begin
original = string
string.gsub!(/(\!{3,})|(\?{3,})/) { |s| s.length.even? ? s : '' }
end until original == string
string
end
puts remove("!????!!!?").inspect # answer == "!"
puts remove("!???!!").inspect # answer == ""
puts remove("!????!!").inspect # answer == "!????!!"
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 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