Case Statement using || (OR) - ruby

The following code I am trying to use to assign an email alias via an api to our ticketing system.
#email.cc_list = case #site_id
when /site1/ || /site2/; "smail-alias-1"
when /site3/ || /site4/ || /site5/ || /site6/; "email-alias-2"
when /site7/ || /site8/; "email-alias-3"
when /site9/; "email-alias-4"
when /site10/; "email-alias-5"
end
the problem is that only site 1, 3, 7, 9, and 10 are actually being assigned properly. anything after the || isn't working.
I would rather avoid 10 when statements for 5 alias's. Is there a way that I can make this case statement work with a hash in order to get the system to determine when it matches the specified site_id? or another way to make the or functions work?

You could write :
#email.cc_list = case #site_id
when /site(1|2)/ then "smail-alias-1"
when /site(3|4|5|6)/ then "email-alias-2"
when /site(7|8)/ then "email-alias-3"
when /site9/ then "email-alias-4"
when /site10/ then "email-alias-5"
end

Not to give you the correct ways since others have done that, but will be good for your knowledge why your original code fails.
case #site_id
when /site1/ || /site2/ ...
does not translate to:
if #site_id =~ /site1/ || #site_id =~ /site2/ ...
but to:
if #site_id =~ /site1/ || /site2/ ...
which is parsed as:
if ((#site_id =~ /site1/) || /site2/) ...
so, when the first match fails, it returns nil. nil ||-ed with a regex object has the value of regex object itself. A regex object in condition has boolean value of... you guess: false
you will even get a:
warning: regex literal in condition
if you do it directly in an if statement.

You might prefer to write:
#email.cc_list = case #site_id[/\d+/].to_i
when 1,2 then "smail-alias-1"
when 3..6 then "email-alias-2"
when 7,8 then "email-alias-3"
when 9 then "email-alias-4"
when 10 then "email-alias-5"
end

You could join your regexes w/ Regexp.union:
#email.cc_list = case #site_id
when Regexp.union(/site1/, /site2/); "smail-alias-1"
when Regexp.union(/site3/, /site4/, /site5/, /site6/); "email-alias-2"
when Regexp.union(/site7/, /site8/); "email-alias-3"
when /site9/; "email-alias-4"
when /site10/; "email-alias-5"
end
Or make the regex like /site1|site2/ yourself which is what union would basically do for you here.

Related

Ruby if statement to exclude multiple string variations

I'm trying to parse an array that I've created to ultimately write the 'good' values to a file. The array may look something like this, however the contents may change, so I can't match for a certain value:
array = ["10.10.10.0/24", "10.10.10.1/32", "10.10.10.129/32", "127.0.0.0/8", "169.254.0.0/16", "192.168.1.0/24", "255.255.255.255/32"]
I believe that it makes sense to check the array values before writing to the file and not write the values I know that I don't want. In this case, the values would always be:
10.10.10.1/32
10.10.10.129/32
127.0.0.0/8
169.254.0.0/16
255.255.255.255/32
My initial if statement looked like this, which sort of accomplished what I am after, but not completely:
if !network.include?("/32" || "127.0.0.0/8" || "169.254.0.0/16" || "255.255.255.255/32")
file.write("#{network}\n")
end
Which results in (lines 2 & 3 shouldn't have been included):
10.10.10.0/24
127.0.0.0/8
169.254.0.0/16
192.168.1.0/24
What have I done wrong? Is there a better way to perform the lookup/matching/exclusion?
networks = ["10.10.10.0/24", "10.10.10.1/32", "10.10.10.129/32", "127.0.0.0/8", "169.254.0.0/16", "192.168.1.0/24", "255.255.255.255/32"]
banned_networks = [/\/32/, "127.0.0.0/8", "169.254.0.0/16", "255.255.255.255/32"]
networks.reject do |e|
case e
when *banned_networks
true
end
end.each {|network| file.write("#{network}\n")}
You can't use "or" || like that.
Better might be...
exclude_entries = [ '/32',
'127.0.0.0/8',
'169.254.0.0/16',
'255.255.255.255/32'
]
match_pattern = Regex.new(exclude_entries.join('|'))
(array.reject{|n| n =~ match_pattern}.each do |network|
file.write("#{network}\n")
end
The problem is that the expression "/32" || "127.0.0.0/8" always returns "/32" ... the "or" just returns the first "truthy" value and "/32" is "truthy"
Edited to use regular expression so as to exclude partial text.

Ruby gsub / regex with several arguments [duplicate]

This question already has answers here:
Match a string against multiple patterns
(2 answers)
Closed 8 years ago.
I'm new to ruby and I'm trying to solve a problem.
I'm parsing through several text field where I want to remove the header which has different values. It works fine when the header always is the same:
variable = variable.gsub(/(^Header_1:$)/, '')
But when I put in several arguments it doesn't work:
variable = variable.gsub(/(^Header_1$)/ || /(^Header_2$)/ || /(^Header_3$)/ || /(^Header_4$)/ || /^:$/, '')
You can use Regexp.union:
regex = Regexp.union(
/^Header_1/,
/^Header_2/,
/^Header_3/,
/^Header_4/,
/^:$/
)
variable.gsub(regex, '')
Please note that ^something$ will not work on strings containing something more than something :)
Cause ^ is for matching beginning of string and $ is for end of string.
So i intentionally removed $.
Also you do not need brackets when you only need to remove the matched string.
You can also use it like this:
headers = %w[Header_1 Header_2 Header_3]
regex = Regexp.union(*headers.map{|s| /^#{s}/}, /^\:$/, /etc/)
variable.gsub(regex, '')
And of course you can remove headers without explicitly define them.
Most likely there are a white space after headers?
If so, you can do it as simple as:
variable = "Header_1 something else"
puts variable.gsub(/(^Header[^\s]*)?(.*)/, '\2')
#=> something else
variable = "Header_BLAH something else"
puts variable.gsub(/(^Header[^\s]*)?(.*)/, '\2')
#=> something else
Just use a proper regexp:
variable.gsub(/^(Header_1|Header_2|Header_3|Header_4|:)$/, '')
If the header is always the same format of Header_n, where n is some integer value, then you can simplify your regex greatly:
/Header_\d+/
will find every one of these:
%w[Header_1 Header_2 Header_3].grep(/Header_\d+/)
[
[0] "Header_1",
[1] "Header_2",
[2] "Header_3"
]
Tweaking it to handle finding words, not substrings:
/^Header_\d+$/
or:
/\bHeader_\d+\b/
As mentioned, using Regexp.union is a good start, but, used blindly, can result in very slow or inefficient patterns, so think ahead and help out the engine by giving it useful sub-patterns to work with:
values = %w[foo bar]
/Header_(?:\d+|#{ values.join('|') })/
=> /Header_(?:\d+|foo|bar)/
Unfortunately, Ruby doesn't have the equivalent to Perl's Regexp::Assemble module, which can build highly optimized patterns from big lists of words. Search here on Stack Overflow for examples of what it can do. For instance:
use Regexp::Assemble;
my #values = ('Header_1', 'Header_2', 'foo', 'bar', 'Header_3');
my $ra = Regexp::Assemble->new;
foreach (#values) {
$ra->add($_);
}
print $ra->re, "\n";
=> (?-xism:(?:Header_[123]|bar|foo))

ruby boolean operator or || difference [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Ruby: difference between || and 'or'
In ruby, isn't 'or' and '||' the same thing? I get different results when I execute the code.
line =""
if (line.start_with? "[" || line.strip.empty?)
puts "yes"
end
line =""
if (line.start_with? "[" or line.strip.empty?)
puts "yes"
end
No, the two operators have the same effect but different precedence.
The || operator has very high precedence, so it binds very tightly to the previous value. The or operator has very low precedence, so it binds less tightly than the other operator.
The reason for having two versions is exactly that one has high precedence and the other has low precedence, since that is convenient.
In the first case you used || wich is evaluated prior than anything else in the statement due to the precedence well stated by other answeres, making it clearer with some parenthesis added, your first statement is like:
(line.start_with? ("[" || line.strip.empty?))
wich translates to
(line.start_with? ("["))
resulting FALSE
In the other hand, your second statement translates to
((line.start_with? "[") or line.strip.empty?)
wich translates to
(FALSE or TRUE)
resulting true
That´s why I try to use parenthesis everytime I call a function. :-)
Daniel is right, more clearly:
if (line.start_with?("[") || line.strip.empty?)
puts "yes"
end
will produce yes

Checking if a string has balanced parentheses

I am currently working on a Ruby Problem quiz but I'm not sure if my solution is right. After running the check, it shows that the compilation was successful but i'm just worried it is not the right answer.
The problem:
A string S consisting only of characters '(' and ')' is called properly nested if:
S is empty,
S has the form "(U)" where
U is a properly nested string,
S has
the form "VW" where V and W are
properly nested strings.
For example, "(()(())())" is properly nested and "())" isn't.
Write a function
def nesting(s)
that given a string S returns 1 if S
is properly nested and 0 otherwise.
Assume that the length of S does not
exceed 1,000,000. Assume that S
consists only of characters '(' and
')'.
For example, given S = "(()(())())"
the function should return 1 and given
S = "())" the function should return
0, as explained above.
Solution:
def nesting ( s )
# write your code here
if s == '(()(())())' && s.length <= 1000000
return 1
elsif s == ' ' && s.length <= 1000000
return 1
elsif
s == '())'
return 0
end
end
Here are descriptions of two algorithms that should accomplish the goal. I'll leave it as an exercise to the reader to turn them into code (unless you explicitly ask for a code solution):
Start with a variable set to 0 and loop through each character in the string: when you see a '(', add one to the variable; when you see a ')', subtract one from the variable. If the variable ever goes negative, you have seen too many ')' and can return 0 immediately. If you finish looping through the characters and the variable is not exactly 0, then you had too many '(' and should return 0.
Remove every occurrence of '()' in the string (replace with ''). Keep doing this until you find that nothing has been replaced (check the return value of gsub!). If the string is empty, the parentheses were matched. If the string is not empty, it was mismatched.
You're not supposed to just enumerate the given examples. You're supposed to solve the problem generally. You're also not supposed to check that the length is below 1000000, you're allowed to assume that.
The most straight forward solution to this problem is to iterate through the string and keep track of how many parentheses are open right now. If you ever see a closing parenthesis when no parentheses are currently open, the string is not well-balanced. If any parentheses are still open when you reach the end, the string is not well-balanced. Otherwise it is.
Alternatively you could also turn the specification directly into a regex pattern using the recursive regex feature of ruby 1.9 if you were so inclined.
My algorithm would use stacks for this purpose. Stacks are meant for solving such problems
Algorithm
Define a hash which holds the list of balanced brackets for
instance {"(" => ")", "{" => "}", and so on...}
Declare a stack (in our case, array) i.e. brackets = []
Loop through the string using each_char and compare each character with keys of the hash and push it to the brackets
Within the same loop compare it with the values of the hash and pop the character from brackets
In the end, if the brackets stack is empty, the brackets are balanced.
def brackets_balanced?(string)
return false if string.length < 2
brackets_hash = {"(" => ")", "{" => "}", "[" => "]"}
brackets = []
string.each_char do |x|
brackets.push(x) if brackets_hash.keys.include?(x)
brackets.pop if brackets_hash.values.include?(x)
end
return brackets.empty?
end
You can solve this problem theoretically. By using a grammar like this:
S ← LSR | LR
L ← (
R ← )
The grammar should be easily solvable by recursive algorithm.
That would be the most elegant solution. Otherwise as already mentioned here count the open parentheses.
Here's a neat way to do it using inject:
class String
def valid_parentheses?
valid = true
self.gsub(/[^\(\)]/, '').split('').inject(0) do |counter, parenthesis|
counter += (parenthesis == '(' ? 1 : -1)
valid = false if counter < 0
counter
end.zero? && valid
end
end
> "(a+b)".valid_parentheses? # => true
> "(a+b)(".valid_parentheses? # => false
> "(a+b))".valid_parentheses? # => false
> "(a+b))(".valid_parentheses? # => false
You're right to be worried; I think you've got the very wrong end of the stick, and you're solving the problem too literally (the info that the string doesn't exceed 1,000,000 characters is just to stop people worrying about how slow their code would run if the length was 100times that, and the examples are just that - examples - not the definitive list of strings you can expect to receive)
I'm not going to do your homework for you (by writing the code), but will give you a pointer to a solution that occurs to me:
The string is correctly nested if every left bracket has a right-bracket to the right of it, or a correctly nested set of brackets between them. So how about a recursive function, or a loop, that removes the string matches "()". When you run out of matches, what are you left with? Nothing? That was a properly nested string then. Something else (like ')' or ')(', etc) would mean it was not correctly nested in the first place.
Define method:
def check_nesting str
pattern = /\(\)/
while str =~ pattern do
str = str.gsub pattern, ''
end
str.length == 0
end
And test it:
>ruby nest.rb (()(())())
true
>ruby nest.rb (()
false
>ruby nest.rb ((((()))))
true
>ruby nest.rb (()
false
>ruby nest.rb (()(((())))())
true
>ruby nest.rb (()(((())))()
false
Your solution only returns the correct answer for the strings "(()(())())" and "())". You surely need a solution that works for any string!
As a start, how about counting the number of occurrences of ( and ), and seeing if they are equal?

Regular expression help

I am currently doing a bunch of processing on a string using regular expressions with gsub() but I'm chaining them quite heavily which is starting to get messy. Can you help me construct a single regex for the following:
string.gsub(/\.com/,'').gsub(/\./,'').gsub(/&/,'and').gsub(' ','-').gsub("'",'').gsub(",",'').gsub(":",'').gsub("#39;",'').gsub("*",'').gsub("amp;",'')
Basically the above removes the following:
.com
.
,
:
*
switches '&' for 'and'
switches ' ' for '-'
switches ' for ''
Is there an easier way to do this?
You can combine the ones that remove characters:
string.gsub(/\.com|[.,:*]/,'')
The pipe | means "or". The right side of the or is a character class; it means "one of these characters".
A translation table is more scalable as you add more options:
translations = Hash.new
translations['.com'] = ''
translations['&'] = 'and'
...
translations.each{ |from, to| string.gsub from, to }
Building on Tim's answer:
You can pass a block to String.gsub, so you could combine them all, if you wanted:
string.gsub(/\.com|[.,:*& ']/) do |sub|
case(sub)
when '&'
'and'
when ' '
'-'
else
''
end
end
Or, building off echoback's answer, you could use a translation hash in the block (you may need to call translations.default = '' to get this working):
string.gsub(/\.com|[.,:*& ']/) {|sub| translations[sub]}
The biggest perk of using a block is only having one call to gsub (not the fastest function ever).
Hope this helps!

Resources