How to make this regex rule case insensitive - ruby-on-rails

I'm doing the following:
email = 'bob#luv.southwest.com'
domain_rules = [/craigslist.org/, /evite.com/, /ziprealty.com/, /alleyinsider.com/, /fedexkinkos.com/, /luv.southwest.com/, /fastsigns.com/, /experts-exchange.com/, /feedburner.com/]
user, domain = email.split('#')
domain_rules.each { |rule| return true if !domain.match(rule).nil? }
Problem is this is case sensitive. Is there a way to make this all case insensative, without having to add /i to the end of every single rule?

Use the option "i" (ignore case)
domain_rules = [
/craigslist.org/i,
/evite.com/i,
/ziprealty.com/i,
/alleyinsider.com/i,
/fedexkinkos.com/i,
/luv.southwest.com/i,
/fastsigns.com/i,
/experts-exchange.com/i,
/feedburner.com/i
]
test it here... http://rubular.com/

downcase the email & domain you want to match first, then find_all regexp matches.
You can use find to only retrieve the first matching "rule".
email = 'bob#luv.southwest.com'
domain_rules = [/craigslist.org/, /evite.com/, /ziprealty.com/, /alleyinsider.com/, /fedexkinkos.com/, /luv.southwest.com/, /fastsigns.com/, /experts-exchange.com/, /feedburner.com/]
user, domain = email.split('#').collect { |s| s.downcase }
p domain_rules.find_all { |rule| domain[rule] }
There's also no real need for Regexp:
email = 'bob#luv.southwest.com'
matchable_domains = %w{ craigslist.org evite.com ziprealty.com alleyinsider.com fedexkinkos.com luv.southwest.com fastsigns.com experts-exchange.com feedburner.com }
user, domain = email.downcase.split('#')
p matchable_domains.find_all { |rule| matchable_domains.include?(domain) }
Or, you can do ONLY Regexp:
email = 'bob#luv.southwest.com'
regexp = /[A-Z0-9._%+-]+#(craigslist\.org|evite\.com|ziprealty\.com|alleyinsider\.com|fedexkinkos\.com|luv\.southwest\.com|fastsigns\.com|experts-exchange\.com|feedburner\.com)/
p regexp === email # => true
p regexp.match(email) # => #<MatchData "bob#luv.southwest.com" 1:"bob" 2:"luv.southwest.com">il

No need to use regexes for simple string comparisons.
email = 'bob#luv.southwest.com'
domains = %w(CraigsList.org evite.com ZiPreAltY.com alleyinsider.com fedexkinkos.com luv.southwest.com fastsigns.com experts-exchange.com feedburner.com)
user, user_domain = email.split('#')
p domains.any? { |domain| domain.casecmp(user_domain).zero? }
String#casecmp does a case-insensitive comparison.

You could just make the email address lowercase.

One problem I see with your current implementation is that it will match domains like luvesouthwestlcom.com, because . matches any character. You could deal with this by escaping all the url you are using by doing something like this:
email = 'bob#luv.southwest.com'
domains = %w[craigslist.org evite.com ziprealty.com alleyinsider.com fedexkinkos.com luv.southwest.com fastsigns.com experts-exchange.com feedburner.com]
domain_rules = domains.map{|d| /#{Regexp.escape(d)}/i }
user, domain = email.split('#')
domain_rules.any? { |rule| domain.match(rule) }
Also, if you are only looking for exact matches, you don't really need regular expressions and could just check to see if the email's domain includes one of the strings you are looking for.
email = 'bob#luv.southwest.com'
domains = %w[craigslist.org evite.com ziprealty.com alleyinsider.com fedexkinkos.com luv.southwest.com fastsigns.com experts-exchange.com feedburner.com]
user, domain = email.split('#')
domain.downcase! # lower cases the string in place
domains.any? { |rule| domain.include?(rule) }
The issue with either of these is that they will match anything with an exact string in it, so 'craigslist.org' will match 'nyc.craiglist.org' and 'craigslist.org.uk'. If you want exact matches, you could just use == after downcasing your input domain. e.g.
domains.any? { |rule| domain == rule }

You could pass the rules as simple strings and construct the regex on the fly:
email = 'bob#luv.southwest.com'
domains = %w(craigslist.org evite.com ziprealty.com) # etc
user, domain = email.split('#').collect { |s| s.downcase }
p domains.any? { |d| domain.match(/#{d}/i) }

Related

How to check if each word in an array contains a substring and reject those in Ruby on Rails?

a = ["SUPER", "SOME_VALID", "ROME_INVALID", "SUPER_GOOD"]
a = a.reject { |x| x.in? ["GOOD", "VALID"]}
#=> ["SUPER", "SOME_VALID", "ROME_INVALID", "SUPER_GOOD"]
I don't want words that contain substring VALID or GOOD.
Output should be ["SUPER"] only.
grep_v would work:
a = ["SUPER", "SOME_VALID", "ROME_INVALID", "SUPER_GOOD"]
a = a.grep_v(/GOOD|VALID/)
#=> ["SUPER"]
You could say this:
a = a.reject { |x| x.include?("GOOD") || x.include?("VALID")}
What in? does is to check if the receiver is present in the array passed as argument, meaning:
1.in?([1, 2]) # true
3.in?([1, 2]) # false
That's to say, it checks for the "whole" object, rather than a part of it.
If you want to reject the elements in your array that match with VALID and/or GOOD, you can use =~:
["SUPER", "SOME_VALID", "ROME_INVALID", "SUPER_GOOD"].reject { |word| word =~ /VALID|GOOD/ } # ["SUPER"]
Notice, this is also going to reject words like "VALIDITY", "GOODNESS", etc.
You could use include?:
a.reject { |x| ["GOOD", "VALID"].any?{ |word| x.include?(word) } }
#=> ["SUPER"]

How to extract given array of string with numbers from string in groovy

I'm trying to check if commit-msg from git contains particular ticket number with project key of Jira using groovy in Jenkins pipeline
def string_array = ['CO', 'DEVOPSDESK', 'SEC', 'SRE', 'SRE00IN', 'SRE00EU', 'SRE00US', 'REL']
def string_msg = 'CO-10389, CO-10302 new commit'
To extract numbers I am using below logic.
findAll( /\d+/ )*.toInteger()
Not sure how to extract exact ticket number with project key.
Thanks in advance.
You could use Groovy's find operator - =~, combined with a findAll() method to extract all matching elements. For that, you could create a pattern that matches CO-\d+ OR DEOPSDESK-\d+ OR ..., and so on. You could keep project IDs in a list and then dynamically create a regex pattern.
Consider the following example:
def projectKeys = ['CO', 'DEVOPSDESK', 'SEC', 'SRE', 'SRE00IN', 'SRE00EU', 'SRE00US', 'REL']
def commitMessage = 'CO-10389, CO-10302 new commit'
// Generate a pattern "CO-\d+|DEVOPSDEKS-\d+|SEC-\d+|...
def pattern = projectKeys.collect { /${it}-\d+/ }.join("|")
// Uses =~ (find) operator and extracts matching elements
def jiraIds = (commitMessage =~ pattern).findAll()
assert jiraIds == ["CO-10389","CO-10302"]
// Another example
assert ("SEC-1,REL-2001 some text here" =~ pattern).findAll() == ["SEC-1","REL-2001"]
The regex can be assembled a bit simpler:
def projectKeys = ['CO', 'DEVOPSDESK', 'SEC', 'SRE', 'SRE00IN', 'SRE00EU', 'SRE00US', 'REL']
def commitMessage = 'CO-10389, REL-10302 new commit'
String regex = /(${projectKeys.join('|')})-\d+/
assert ['CO-10389', 'REL-10302'] == (commitMessage =~ regex).findAll()*.first()
You can have also another option with finer contol over matching:
def res = []
commitMessage.eachMatch( regex ){ res << it[ 0 ] }
assert ['CO-10389', 'REL-10302'] == res

Check whether a string contains numbers

I have input values like:
string = "devid"
string = "devid123"
string = "devid.123.devid"
I need to sort strings that contain .(number)., for example "devid.123.devid". How can I separate only strings that consist of .(numbers). like .123.? Help me find a solution.
In a controller, I have:
#person = Person.new
personname = params['personname']
if personname.match("/\d+/")
#person.person_name = personname
#person.save()
result = 'true'
end
When I execute this code, I get "devid123" and "devid.123.devid".
If its certain that the format of the valid personname is always
<string>.<number>.<string>
You can try using :[regex, index] method for strings in ruby.
https://ruby-doc.org/core-2.6.1/String.html#method-i-5B-5D
So if
personname = "devid.123.devid"
s[/(.*)(\.\d+\.)(.*)/, 2] = ".123."
There are three different groups in the regex (.*)(\.\d+\.)(.*).
Matches anything
Matches a .<number>.
Matches anything
So based on this regex, the second group should provide you .<number>. which, I hope, is what you need.
Tested with Ruby 2.4.1
If I understand this correctly you only want a string where the digits are preceded by .. If so you need to modify your regex to be /\.\d+/
#person = Person.new
personname=params['personname']
if personname.match("/\.\d+/")
#person.person_name = personname
#person.save
result = 'true'
end
But this sounds like logic you should be handling in the model, since this is tagged as rails and not plain old ruby
controller
class PersonController
def create
if #person = Person.create(params)
result = 'true'
else
result = 'false'
end
# whatever you doing with result
end
end
person.rb
class Person < ApplicationRecord
validates :personname, format: { with: /\.\d+\./, message: 'must include digits' }
end
You can play with the regex # rubular

Camelize up to a certain part of a string

I have:
s = "like_so__case"
camelize gives this:
s.camelize # => "LikeSoCase"
I'm looking for conversion up to a double underscore __ to get:
"LikeSo__case"
How can I camelize only up to a certain part of a string?
The simplest option is to gsub part of your string.
'like_so__case'.gsub(/(.*?)(__.*)/) { "#{$1.camelize}#{$2}" }
#=> "LikeSo__case"
UPDATE
Cleaner and faster way arising from comments.
'like_so__case__h'.sub(/(.*?)(?=__)/, &:camelize)
#=> "LikeSo__case__h"
s = "like_so__case"
=> "like_so__case"
s.split('__', 2).tap { |s| s[0] = s[0].camelize }.join('__')
=> "LikeSo__case"
You of course could wrap it in string method
For getting this LikeSo__case, we can do like:
s="like_so__case"
s.split('__').tap { |s| s[0] = s[0].camelize }.join('__')
Your description on the demand is not so clear.
From your excepted result, I understand it as 'camelize a part of string until a pattern'. I should note one thing first that camelize is not part of Ruby's standard library of class String. ActiveSupport::Inflector provides it.
So if you want to just camelize each part divided by a pattern, use str.split('_').map(&:capitalize).join('_'). In your case, it returns 'Like_So__Case'.
Ruby's String has another instance method named partition, which splits the string into three parts (an array):
Part before the pattern
The pattern
Part after the pattern
So str.partition('__').tap { |a| a[0] = a[0].split('_').map(&:capitalize).join }.join should be your answer in plain Ruby.
No need of relying on camelize. Simply, this:
"like_so__case"
.gsub(/_?([a-z])([a-z]*)(?=.*__)/i){$1.upcase + $2.downcase}
# => "LikeSo__case"
def camelize(s)
for i in 0..s.size-2 do
if s[i] == "_" and s[i+1] == "_"
next
elsif s[i] == "_" and s[i+1] != "_" and s[i-1] != "_"
s[i+1] = s[i+1].upcase
s[i] = ""
else
next
end
end
return s
end
Use this method to solve your problem
s = "like_so__case"
i = s.index('__')
#=> 7
s.tap { |s| s[0,i] = s[0,i].camelize }
#=> LikeSo__case
The last line could be replaced by two lines:
s[0,i] = s[0,i].camelize
s
If the original string is not to be mutated write
s.dup.tap { |s| s[0,i] = s[0,i].camelize }

Conditionally add OR condition in query

The orders table have a few columns, say email, tel and address.
User provides email/tel/address, and any of them can be nil or empty string (EDITED).
How to generate an OR query, so if any of the columns match, the record is returned?
The only catch is that if any value provided is nil or empty, that will be ignored instead.
I was able to do the following using Arel:
email = params[:email]
tel = params[:tel]
address = params[:address]
t = Order.arel_table
sq = t[:email].eq(email) if email.present?
sq = sq.or(t[:phone].eq(phone)) if phone.present?
sq = sq.or(t[:phone].eq(address)) if address.present?
Order.where( sq )
However it will err if email is nil, because sq will not instantiate.
I want to prevent constructing sql string, and I use Squeel gem.
you can put
Order.where("email=? or tel= ? or address=?", params[:email], params[:tel], params[:address])
You can check whether your params are nil or not by Ick's maybe. So read about Ick gem and follow the steps given there and then you can use it in your case like :
params[:email].maybe
params[:tel].maybe
params[:address].maybe
Hope, this is what you were looking for.
Please have a try with
where_condition = "true"
where_condition += "OR email = '#{params[:email]}'" if params[:email].present?
where_condition += "OR tel = '#{params[:tel]}'" if params[:tel].present?
where_condition += "OR address = '#{params[:address]}'" if params[:address].present?
Order.where(where_condition)
In order to prevent nil or empty string, I finally got the following:
t = Order.arel_table
conditions = [:email, :phone, :address].map{|attr|
attr_value = params[attr]
if attr_value.present?
t[attr].eq(attr_value)
else
nil
end
}.compact
if conditions.empty?
Order.where('1=0')
else
Order.where( conditions.inject{|c, cc| c.or(cc).expr} )
end
Ugly, but flexible.

Resources