I don't know how pattern matching works in Ruby 2.
I have the following value, targetfilename = /mnt/usb/mpeg4Encoded.mpeg4
My pattern matching if-else is thus:
if (targetfilename.match(/^\//))
puts "amit"
else
puts "ramit"
The output is ramit.
I don't understand how this pattern matching works though.
if targetfilename.match(/^V/)
puts "amit"
else
puts "ramit"
end
# result:
# "amit"
Why is this? This is because targetfilename.match(/^V/) outputs a Matchdata object (click on the link for a full description of this object). This is an object that contains all of the information that is in the "matching". If there is no match, no MatchData object is returned, because there's nothing to return. Instead, you get nil.
When you use if, if it tries to compare a nil, it treats it the same way as false.
Basically, any "actual" value (besides false) is treated the same way as true. Basically, it's asking
if (there's anything here)
do_this
else
do_something_else
end
Again, let me reiterate:
If the thing after if is either false or nil, the if statement resolves to the "else".
If it's anything else, it resolves as if it had gotten a "true" statement.
Regular Expressions
/^V/ is what is called a "Regular Expression"; the // is a Regexp literal the same way that the "" is a String literal, and Regexps are represented by the Regexp class the same way that strings are represented by the String class.
The actual "regular expression" is what's between the slashes -- ^V. This is saying:
^: the start of a string
V: a capital letter V
So, /^V/ will match any cases of the capital letter "V" at the beginning of a string.
What else can you put in a regular expression? What are the special characters? Try this regexp cheat sheet
Also, some great tools:
Rubular -- enter in your regular expression, and then a same text, and see what matches.
Strfriend -- enter in a regular expression and see it "visually" represented.
Related
EDIT: My original question turned out not to be related to my actual problem, but as I learned something in the process, I decided to rephrase my initial statement.
I wanted to replace each space with a _ within a pair of brackets in a string. Here is my example input:
This is my string (nice, isn't it?). It can have various types [of input].
Desired output:
This is my string (nice,_isn't_it?). It can have various types [of_input].
I have the following code:
my_string = my_string.gsub(/\([^\(\)]+\)|\[[^\[\]]+\]/) { |bracketed|
bracketed.gsub(/ /, '_')
}
Why does bracketed.gsub(/ /, '_') equal to bracketed = bracketed.gsub(/ /, '_')? How is that different from gsub!? I don't fully understand the logic behind Ruby's assumption what to return here.
Why does bracketed.gsub(/ /, '_') equal to bracketed = bracketed.gsub(/ /, '_')? How is that different from gsub!?
gsub returns a new string.
gsub! changes the existing string.
So bracketed = bracketed.gsub(/ /, '_') and bracketed.gsub!(/ /, '_') are pretty much equivalent.
(There is only a minor behavioural difference in that gsub! will return nil if no pattern was matched. But either way, you'll mutate the original bracketed variable in the same way.)
However, you're asking the wrong question... Let's look again at your original code, which could be written as:
my_string.gsub!(/\([^)]+\)|\[[^\]]+\]/) do |bracketed|
bracketed.gsub(/ /, '_')
end
From the documentation for String#gsub:
In the block form, the current match string is passed in as a parameter [...] The value returned by the block will be substituted for the match on each call.
In ruby, the final evaluated line in a method/block is its implicit return value. All you are doing here is passing a value back up to the original gsub method; it doesn't matter whether or not you mutate/reassign the bracketed variable.
Perhaps this example will make things a little clearer:
"hello (world)".gsub!(/\([^)]+\)|\[[^\]]+\]/) do |bracketed|
bracketed = "something different"
"TEST!!!"
end
# => "hello (TEST!!!)"
So I've got an issue where my regex looks like this: /true|false/.
When I check the word falsee I get a true from this regex, is there a way to just limit it to the exact true or false words?
Use this regex:
/^(true|false)$/
It will match the beginning and end of the test string with ^ and $, respectively, so nothing else can be in the string (exact match).
See live example at Regex101.
UPDATE (see #w0lf's comment): The parentheses are to isolate the true|false clause so that they are not grouped incorrectly. (This also puts the true or false match in the first capturing group, but since it seems that you are only matching and not capturing an output, this should not make a difference).
Alternatively, if you simply want to match two values, there are easier ways in Ruby. #SimoneCarletti suggests one. You can also use the basic == or eql? operators. Try running the following script to see that these all work:
values = ["true", "false", "almosttrue", "falsealmost"]
values.each do | value |
puts value
# these three are all equivalent
puts "match with if" if value == "true" || value == "false"
puts "match with equals?" if (value.eql? "true") || (value.eql? "false")
puts "match with regex" if /^(true|false)$/.match value
puts
end
You need to use the ^ and $ anchors:
/^(true|false)$/
Edit: As Cary pointed out in the comments, the pattern above will also match multiline strings that happen to contain a line with true or false. To avoid this, use the \A and \z delimiters that match the beginning and end of string respectively:
/\A(true|false)\z/
Try out
/^(true|false)$/
where ^ is the start of a line and $ the end.
You can use
/^(true|false)$/
or even better
/\A(true|false)\z/
that will match the beginning and end of the string (instead of line). If you only need to match for whose words, it may be more efficient to use a simple array and include?:
%w( true false ).include?(value)
I am going through the Peter Cooper book "Beginning Ruby" and I have some questions regarding some of the string methods and regular expression usage. I think I'm clear on what a regular expression is: "a string that describes a pattern for matching elements in other strings."
So:
"This is a test".scan(/\w\w/) {|x| puts x}
Output:
Th
is
is
te
st
=> "This is a test"
So it prints two characters at a time. I didn't realize it also returns the original string. Why is this?
Also,
"This is a test".scan(/[aeiou]/) { |x| puts x }
What do the brackets do? I think they are called character classes, but I am not sure exactly what they do. The explanation in Cooper's book isn't totally verbose and clear.
Explanation of character classes:
"The last important aspect of regular expressions you need to understand at this stage is
character classes. These allow you to match against a specific set of characters. For example, you can scan through all the vowels in a string:"
Yes, it is called a character class.
A character class defines a set of characters. Saying, "match one character specified by the class". The two implementations of a character class are considered a positive class [ ] and a negative class [^ ]. The positive character class allows you to define a list of characters, any one of which may appear in a string for a match to occur while the negative class allows you to define a list of characters that must NOT appear in a string for a match to occur.
Explanation of your character class:
[aeiou] # any character of: 'a', 'e', 'i', 'o', 'u'
The scan method usually returns an array with the matches, but it optionally accepts a block, which is equivalent to do an each of the resulting array.
Here is the documentation: http://www.ruby-doc.org/core-2.1.3/String.html#method-i-scan
To the second question, #hwnd already gave you a clear answer. The best way to learn this is to experiment, regex101.com is the online tool I usually use. It lists explanations for all your matching elements, so it's a wonderful learning resource too.
Some things you might like to try:
123abab12ab1234 with pattern [123]
123abab12ab1234 with pattern [ab]+
123abab12ab1234 with pattern b[1|a]
One thing to remember is that a character class matches ONE character, for example:
str = 'XXXaeiouXXX'
puts str
str.sub!(/[aeiou]/, '.')
puts str
--output:--
XXXaeiouXXX
XXX.eiouXXX
A character class says, "Match this character OR this character OR this character...ONE TIME ".
Also check out rubular:
http://rubular.com/
I didn't realize it also returns the original string. Why is this?
So that you can chain methods together:
my_str.scan(...).downcase.capitalize.each_char {|char| puts char}.upcase.chomp
I can run a search and find the element I want and can return those words with that letter. But when I start to put arguments in, it doesn't work. I tried select with include? and it throws an error saying, private method. This is my code, which returns what I am expecting:
my_array = ["wants", "need", 3, "the", "wait", "only", "share", 2]
def finding_method(source)
words_found = source.grep(/t/) #I just pick random letter
print words_found
end
puts finding_method(my_array)
# => ["wants", "the", "wait"]
I need to add the second argument, but it breaks:
def finding_method(source, x)
words_found = source.grep(/x/)
print words_found
end
puts finding_method(my_array, "t")
This doesn't work, (it returns an empty array because there isn't an 'x' in the array) so I don't know how to pass an argument. Maybe I'm using the wrong method to do what I'm after. I have to define 'x', but I'm not sure how to do that. Any help would be great.
Regular expressions support string interpolation just like strings.
/x/
looks for the character x.
/#{x}/
will first interpolate the value of the variable and produce /t/, which does what you want. Mostly.
Note that if you are trying to search for any text that might have any meaning in regular expression syntax (like . or *), you should escape it:
/#{Regexp.quote(x)}/
That's the correct answer for any situation where you are including literal strings in regular expression that you haven't built yourself specifically for the purpose of being a regular expression, i.e. 99% of cases where you're interpolating variables into regexps.
Say I build an array like this:
:001 > holder = "This.File.Q99P84.Is.Awesome"
=> "This.File.Q99P84.Is.Awesome"
:002 > name = holder.split(".")
=> ["This", "File", "Q99P84", "Is", "Awesome"]
Now, I can do:
name[2].include? 'Q99P84'
Instead of putting in 'Q99P84' I want to put in something like 'symbol for Q followed by
symbol for number, symbol for number, symbol for P, symbol for number, symbol for number
so the .include? function will be dynamic. So any file name I load that has Q##P## will return true.
I'm pretty sure this is possibly I just don't know exactly what to search. If you know the answer can you link me to the documentation.
What you're looking for is regular expression matching. The Ruby regexp object will help you. What you want is something like
/Q[\d+]P[\d+]/.match(name[2])
...which will return a truthy value if name[2] has a string which matches a character Q, one or more digits (0-9), a character P, then one or more digits. This is probably too flexible a match if the pattern you want has exactly two digits in those number spaces; for that you might try a more specific pattern:
/Q\d\dP\d\d/.match(name[2])
One way to do this is through Regular Expressions ('regex' for short). Two good sources of information is Regular Expression.info and Rubular which is more Ruby centric.
One way to use regex on a string is the String#match method:
names[2].match(/Q\d\dP\d\d/) # /d stands for digit
This will return the string if there is a match and it will return nil if there isn't.
"Q42P67".match(/Q\d\dP\d\d/) #=> "Q42P67"
"H33P55".match(/Q\d\dP\d\d/) #=> nil
This is helpful in an if condition since a returned string is 'truthy' and nil is 'falsely'.
names[2] = "Q42P67"
if names[2].match(/Q\d\dP\d\d/)
# Will execute code here
end
names[2] = "H33P55"
if names[2].match(/Q\d\dP\d\d/)
# Will not execute code here
end
I hope that helps until you dig further into your study of Regular Expressions.
EDIT:
Note that the Q and P in /Q\d\dP\d\d/ are capital letters. If case is not important, you can append an 'i' for case-insensitivity. /Q\d\dP\d\d/i will capture "Q42P67" and "q42P67"