Ruby Mongo mapper contains "abc"? - ruby

Instead of saying:
#b = coll.find("xpto.it" => #email)
if it's equal to #email, how can I look if it contains the string #email?
EDIT
It doesn't work when there's something like:
"Donald Trump <donal#tr.com>"

You can also construct a regular expression dynamically. To match a given search string:
search_string = #email
# Constructor syntax
coll.find({"name" => Regexp.new(search_string)})
# Literal syntax
coll.find({"name" => /#{search_string}/})
Reference:
http://api.mongodb.org/ruby/current/file.TUTORIAL.html

Related

Combination of strings, other variables and regexp in variable declaration

I'm trying to move files to other directories with FileUtils.mv. I'm trying to define a variable called name_convention, which is a mix of strings, other variables and I also want to include a regexp, where I'm failing. My code so far:
#these are my other variables already declared from an array
season = array[11..13]
episode = array[15..17]
#and this is my 'name_convention' variable
name_convention = "friends" + season + episode + "bluray.mkv"
Up to here, everything is working fine. Except that between friends and season, there can be either a . or a _. For example:
friends_s01e01_bluray.mkv
friends.s01e01.bluray.mkv
I tried to use a regexp, like /(\.|-)/, but I got the error: no implicit conversion of regex into string ruby
How can I provide the two options to my name_convention variable, so that it can be applied to both filenames?
You're trying to interpolate a regex into a string, but you need to do the opposite - interpolate the strings into the regex:
season = "s01"
episode = "e01"
regex = /friends[\._]#{Regexp.escape(season)}#{Regexp.escape(episode)}.bluray.mkv/
regex.match "friends_s01e01_bluray.mkv"
# => MatchData
regex.match "friends.s01e01_bluray.mkv"
# => MatchData
regex.match "friends-s01e01_bluray.mkv"
# => nil
For this particular example (s01 and e01) you don't need the Regexp.escape but it's a good idea to include it just in case.
If you're looking for a quick and dirty sNNeNN parser, try this:
def parse_episode(str)
m = str.match(/\A(.*?)[\-\_\.]?(s\d+)(e\d+)[\-\_\.]?(.*)\z/i)
# If matched, strip out the first entry which is the complete match
m&.to_a&.drop(1)
end
Where this produces results like:
parse_episode('snowpiercer-s01e01-stream')
# => ["snowpiercer", "s01", "e01", "stream"]
parse_episode('s01')
# => nil
parse_episode('wilford')
# => nil
parse_episode('simpsons_S04E12_monorail')
# => ["simpsons", "S04", "E12", "monorail"]
parse_episode('simpsons.S04E12')
# => ["simpsons", "S04", "E12", ""]

How to get text between #{...} with RegEx?

I have the next text:
My name is %{name}
how can I get name inside of %{ ... }?
I'm trying with:
/%{(.*)}/
but it takes whole %{name}, but I need just name.
When I try this expression in regex101.com, it gives me 2 cases: Full match({name}) and Group 1(name). In my ruby code it gives me Full case, but I need Group case.
What is the problem?
You can use lookaround:
(?<=%{)[^%]*(?=})
see demo.
(?<=%{) will ensure that the next part is preceded with %{
[^%]* will match avoid issue with encapsulated field
(?=}) will ensure that it's followed by a }
Don't know how you're applying that regex to the string, but .match method returns a MatchData object, from which you can extract matched groups
s = 'My name is %{name}'
regex = /%{(.*)}/
m = s.match(regex) # => #<MatchData "%{name}" 1:"name">
m[0] # => "%{name}"
m[1] # => "name"
It looks nicer with named groups
s = 'My name is %{name}'
regex = /%{(?<var>.*)}/
m = s.match(regex) # => #<MatchData "%{name}" var:"name">
m[:var] # => "name"
In Ruby, you can easily access any capture group you need with
s[/regex/, n]
where n is the ID of the capturing group. So, in your case, use
s[/%{([^}]*)}/, 1]
or
s[/%{(.*?)}/m, 1]
See the online demo
You need to make the Group 1 subpattern lazy or set to match any chars but } to get as few symbols as possible in order not to overflow to the next match.

Check the string with hash key

I am using Ruby 1.9.
I have a hash:
Hash_List={"ruby"=>"fun to learn","the rails"=>"It is a framework"}
I have a string like this:
test_string="I am learning the ruby by myself and also the rails."
I need to check if test_string contains words that match the keys of Hash_List. And if it does, replace the words with the matching hash value.
I used this code to check, but it is returning them empty:
another_hash=Hash_List.select{|key,value| key.include? test_string}
OK, hold onto your hat:
HASH_LIST = {
"ruby" => "fun to learn",
"the rails" => "It is a framework"
}
test_string = "I am learning the ruby by myself and also the rails."
keys_regex = /\b (?:#{Regexp.union(HASH_LIST.keys).source}) \b/x # => /\b (?:ruby|the\ rails) \b/x
test_string.gsub(keys_regex, HASH_LIST) # => "I am learning the fun to learn by myself and also It is a framework."
Ruby's got some great tricks up its sleeve, one of which is how we can throw a regular expression and a hash at gsub, and it'll search for every match of the regular expression, look up the matching "hits" as keys in the hash, and substitute the values back into the string:
gsub(pattern, hash) → new_str
...If the second argument is a Hash, and the matched text is one of its keys, the corresponding value is the replacement string....
Regexp.union(HASH_LIST.keys) # => /ruby|the\ rails/
Regexp.union(HASH_LIST.keys).source # => "ruby|the\\ rails"
Note that the first returns a regular expression and the second returns a string. This is important when we embed them into another regular expression:
/#{Regexp.union(HASH_LIST.keys)}/ # => /(?-mix:ruby|the\ rails)/
/#{Regexp.union(HASH_LIST.keys).source}/ # => /ruby|the\ rails/
The first can quietly destroy what you think is a simple search, because of the ?-mix: flags, which ends up embedding different flags inside the pattern.
The Regexp documentation covers all this well.
This capability is the core to making an extremely high-speed templating routine in Ruby.
You could do that as follows:
Hash_List.each_with_object(test_string.dup) { |(k,v),s| s.sub!(/#{k}/, v) }
#=> "I am learning the fun to learn by myself and also It is a framework."
First, follow naming conventions. Variables are snake_case, and names of classes are CamelCase.
hash = {"ruby" => "fun to learn", "rails" => "It is a framework"}
words = test_string.split(' ') # => ["I", "am", "learning", ...]
another_hash = hash.select{|key,value| words.include?(key)}
Answering your question: split your test string in words with #split and then check whether words include a key.
For checking if the string is substring of another string use String#[String] method:
another_hash = hash.select{|key, value| test_string[key]}

Constructing a format string using variables

String format works like this:
someString = "Example string %{key}"
result = someString % {key: newData}
I would like to retrieve the hash keys in the string without hardcoding them. Is there a method for doing this?
Also, is there any way to construct the format string using variables? I would like to do something like this:
variable = key
result = someString % {variable: newData}
You almost got it. Just a bit off with the syntax
variable = :key # get this one from whereever
someString = "Example string %{key}"
someString % { variable => 'foo' } # => "Example string foo"
One way to extract keys from the format string:
"Example string %{key1} %{key2}".scan /(?<=%{)[^{}]+?(?=})/
# => ["key1", "key2"]
The regex (?<=%{)[^{}]+?(?=}) matches one or more characters (non-greedy) if it's prefixed by %{ and followed by }.
To construct the format string, you can use string interpolation:
variable = 'key'
"Example string %{#{variable}}"
# => "Example string %{key}"

Ruby: How to parse a string to pull something out and assign it to a variable

I have a string that looks something like this:
"my name is: andrew"
I'd like to parse the string, pull out the name from the string, and assign it to a variable. How would I do this with Ruby?
Update:
The string I used as an example was only an example. The strings that I will be working with can change formats, so you can't rely on the colon being in the actual example. Here are a few examples that I'm working with:
"/nick andrew" # command: nick, value: "andrew"
"/join developers" # command: join, value: "developers"
"/leave" # command: leave, value: nil
I'd like to use some sort of regular expression to solve this (since the string can change formats), rather than splitting the string on certain characters or relying on a certain character position number.
s = "my name is: andrew"
p s.split(':')[1].strip # "andrew"
See
split
strip
Another way:
name = "my name is: andrew".split(/: */)[1] # => "andrew"
or
name = "my name is: andrew".split(/: */).last # => "andrew"
Breaking it down, first we break it into parts.
The regular expression /: */ says a : followed by any number of spaces will be our splitter.
"my name is: andrew".split(/: */) # => ["my name is", "andrew"]
Then we select the second item:
["my name is", "andrew"][1] # => "andrew"
This tutorial really helped me understand how to work with regular expressions in Ruby.
One way to use a regular expression to get the string you want is to replace the stuff you don't want with an empty string.
original_string = "my name is: andrew"
name = original_string.sub(/^my name is: /, '') # => 'andrew'
another_format = "/nick andrew"
name = another_format.sub(/^\/nick /, '') # => 'andrew'
However, that's just string replacement/substitution. The regex is not capturing anyting.
To capture a string using a regular expression, you can use the Ruby match method:
original_string = "my name is: andrew"
matches = original_string.match /^my name is: (.*)/
name = matches[1] # return the first match
One way to do that is:
s = "my name is: andrew"
pos = (s =~ /(?!.*:).*/)
result = s[pos..-1]
p result.strip! # "andrew"
Another:
s = "my name is: andrew";
p s.slice(s.index(":")..-1) # "andrew"
s.split.last
That should work with all of your cases.

Resources