Dynamic condition in ruby on rails - ruby-on-rails

I have the following condition:
if "FIX_STRING 0,0,DYNAMIC_STRING" == "FIX_STRING #{integer_from_0_to_5},#{integer_from_0_to_5},#{DYNAMIC_STRING}"
true
else
false
end
How to make it dynamically like this?
if "FIX_STRING 0,0,DYNAMIC_STRING" == "FIX_STRING #{/0|1|2|3|4|5/},#{/0|1|2|3|4|5/},#{/A|B|C|D/}"
true
else
false
end

You're on the right track here, but you've got a very peculiar coding style. The first thing to point out is that a comparison like == already returns a boolean value of true or false, there's no reason for the if which then returns exactly the same thing.
The second thing is that you're comparing a string to another string, so they have to match exactly. Close enough does not count. If you evaluate your other string you get a mess:
"FIX_STRING (?-mix:0|1|2|3|4|5),(?-mix:0|1|2|3|4|5),(?-mix:A|B|C|D)"
Finally, if you're trying to test a string versus a regular expression, you do this:
PATTERN = /\AFIX_STRING [0-5],[0-5],[A-D]\z/
You can test this sort of thing on Rubular to get it right. Here [0-5] means anything in that range. It's short-hand for what you had.
Then you can test arbitrary strings versus this pattern:
"FIX_STRING 3,4,D".match(PATTERN)
# => #<MatchData "FIX_STRING 3,4,D">
So that matched.
Newer versions of Ruby have a match? method that only tests matches, it doesn't return what matched, which you might want to make use of if you're running on 2.3 or later. It's faster than the plain match method, though that only really matters if you're doing a lot of matches inside loops.

Related

Ruby on Rails: Checking for valid regex does not work properly, high false rate

In my application I've got a procedure which should check if an input is valid or not. You can set up a regex for this input.
But in my case it returns false instead of true. And I can't find the problem.
My code looks like this:
gaps.each_index do | i |
if gaps[i].first.starts_with? "~"
# regular expression
begin
regex = gaps[i].first[1..-1]
# a pipe is used to seperate the regex from the solution-string
if regex.include? "|"
puts "REGEX FOUND ------------------------------------------"
regex = regex.split("|")[0..-2].join("|")
end
reg = Regexp.new(regex, true)
unless reg.match(data[i])
puts "REGEX WRONGGGG -------------------"
#wrong_indexes << i
end
rescue
end
else
# normal string
if data[i].nil? || data[i].strip != gaps[i].first.strip
#wrong_indexes << i
end
end
An example would be:
[[~berlin|berlin]]
The left one before the pipe is the regex and the right one next to the pipe is the correct solution.
This easy input should return true, but it doesn't.
Does anyone see the problem?
Thank you all
EDIT
Somewhere in this lines must be the problem:
if regex.include? "|"
puts "REGEX FOUND ------------------------------------------"
regex = regex.split("|")[0..-2].join("|")
end
reg = Regexp.new(regex, true)
unless reg.match(data[i])
Update: Result without ~
The whole point is that you are initializing regex using the Regexp constructor
Constructs a new regular expression from pattern, which can be either a String or a Regexp (in which case that regexp’s options are propagated, and new options may not be specified (a change as of Ruby 1.8).
However, when you pass the regex (obtained with regex.split("|")[0..-2].join("|")) to the constructor, it is a string, and reg = Regexp.new(regex, true) is getting ~berlin (or /berlin/i) as a literal string pattern. Thus, it actually is searching for something you do not expect.
See, regex= "[[/berlin/i|berlin]]" only finds a *literal /berlin/i text (see demo).
Also, you need to get the pattern from the [[...]], so strip these brackets with regex = regex.gsub(/\A\[+|\]+\z/, '').split("|")[0..-2].join("|").
Note you do not need to specify the case insensitive options, since you already pass true as the second parameter to Regexp.new, it is already case-insensitive.
If you are performing whole word lookup, add word boundaries: regex= "[[\\bberlin\\b|berlin]]" (see demo).

Apply modification only to substring in Ruby

I have a string of the form "award.x_initial_value.currency" and I would like to camelize everything except the leading "x_" so that I get a result of the form: "award.x_initialValue.currency".
My current implementation is:
a = "award.x_initial_value.currency".split(".")
b = a.map{|s| s.slice!("x_")}
a.map!{|s| s.camelize(:lower)}
a.zip(b).map!{|x, y| x.prepend(y.to_s)}
I am not very happy with it since it's neither fast nor elegant and performance is key since this will be applied to large amounts of data.
I also googled it but couldn't find anything.
Is there a faster/better way of achieving this?
Since "performance is key" you could skip the overhead of ActiveSupport::Inflector and use a regular expression to perform the "camelization" yourself:
a = "award.x_initial_value.currency"
a.gsub(/(?<!\bx)_(\w)/) { $1.capitalize }
#=> "award.x_initialValue.currency"
▶ "award.x_initial_value.x_currency".split('.').map do |s|
"#{s[/\Ax_/]}#{s[/(\Ax_)?(.*)\z/, 2].camelize(:lower)}"
end.join('.')
#⇒ "award.x_initialValue.x_currency"
or, with one gsub iteration:
▶ "award.x_initial_value.x_currency".gsub(/(?<=\.|\A)(x_)?(.*?)(?=\.|\z)/) do |m|
"#{$~[1]}" << $~[2].camelize(:lower)
end
#⇒ "award.x_initialValue.x_currency"
In the latter version we use global substitution:
$~ is a short-hand to a global, storing the last regexp match occured;
$~[1] is the first matched entity, corresponding (x_)?, because of ? it might be either matched string, or nil; that’s why we use string extrapolation, in case of nil "#{nil}" will result in an empty string;
after all, we append the camelized second match to the string, discussed above;
NB Instead of $~ for the last match, one might use Regexp::last_match
Could you try solmething like this:
'award.x_initial_value.currency'.gsub(/(\.|\A)x_/,'\1#').camelize(:lower).gsub('#','x_')
# => award.x_initialValue.currency
NOTE: for # char can be used any of unused char for current name/char space.

Rails: Given a String, check if an Array (of strings) contains a substring of String

Is there a more Railsy way to do this (without explicit regex, perhaps?):
array_o_strings = ["some strings", "I'd like", "to parse"]
string = "like to parse"
re = Regexp.union(array_o_strings.map { |i| Regexp.new(i) })
string =~ re
Just pining for magical Rails methods.
There's really nothing wrong with using a regular expression here if that's your intent. It's generally more efficient to use one of those than to go through the trouble of comparing arrays.
It's worth noting you don't have to do that much work to get this:
re = Regexp.union(array)
That should handle automatically escaping those strings and compiling them into a singular regular expression. Test with strings containing * and ? to be sure.
One note to add on style is that the =~ operator is a hold-over from Perl. It's preferable to use string.match(re) to make it clear what's going on there.
How big is the array? It may be worth comparing the speed using a regex vs checking each element. If the array is sorted shortest to longest that would help when checking one by one as you're more likely to find a match first.
In any event, this is one way:
array_o_strings.any?{|e| string.index(e) }

Regex problem with match method

I want validate many mails ( one or more) with regex expression but this attribute don´t belongs to any model. So I wrote a method:
def emails_are_valid?(emails)
#regex with validation
regex = Regexp.new("^(\s*[a-zA-Z0-9\._%-]+#[a-zA-Z0-9\.-]+\.[a-zA-Z]{2,4}\s*([,]{1}[\s]*[a-zA-Z0-9\._%-]+#[a-zA-Z0-9\.-]+\.[a-zA-Z]{2,4}\s*)*)$")
#if the quantity of emails is zero o its validations is bad return false.
if emails.blank? || emails.match(regex).nil?
return false
else
return true
end
end
I evaluate this string mm#somedomain.com aa, mma#somedomain.com when
I tested this regex in http://www.rubular.com/ is bad (no matches).
So According to this page my regex is ok.
But when I evaluate emails.match(regex).nil? that returns me false (So the string is valid, but this string is bad)
Please I need help. my regex is bad or my emails_are_valid? method is bad or match method is bad.
Thanks in advance.
You should have used single quotes instead of double quotes when declaring your regex, otherwise \s gets parsed as an escape sequence.
Change that line to
regex = Regexp.new('^(\s*[a-zA-Z0-9\._%-]+#[a-zA-Z0-9\.-]+\.[a-zA-Z]{2,4}\s*([,]{1}[\s]*[a-zA-Z0-9\._%-]+#[a-zA-Z0-9\.-]+\.[a-zA-Z]{2,4}\s*)*)$')
and the method will work.
On a side note, this would be a more concise way of doing the same thing - http://codepad.org/YbsqIkcP

urls from gsub not correct

I have some problems when I try to check urls after I get them using the gsub method.
From the console it works fine:
('http://ale.it' =~ URI::regexp).nil?.to_s
=> "false"
but if i launch this it doesn't work:
"http://ale.it".gsub(/http[s]?:\/\/[^\s]+/, ('\0' =~ URI::regexp).nil?.to_s)
=> "true"
How can I get correct urls?
This is an explanation of what your 2 examples do. Whilst it isn't really an answer it's a bit long to fit in a comment.
=~ returns the position where a match occurs or nil if no match is found.
In your first example 'http://ale.it' matches URI::regexp starting at position 0 so you get 0.nil? which is false, converted to a string "false"
gsub in your second example takes 2 parameters, a pattern and a replacement string and replaces all matches of the pattern with the replacement.
'\0' doesn't match URI::regexp so ('\0' =~ URI::regexp).nil? is true and with to_s applied is the string "true".
"http://ale.it" matches /http[s]?:\/\/[^\s]+/ so gets replaced with "true".
You will have to expand your question to explain what you're trying to achieve.
i solved with:
"http://ale.it".gsub(/http[s]?:\/\/[^\s]+/) do |m|
(m =~ URI::regexp).nil?.to_s)
end

Resources