matching a double-quote via quote vs pattern - ruby

Why does check_char1 fail to find the double-quote?
#!/usr/bin/env ruby
line = 'hello, "bob"'
def check_char1(line, _char)
puts "check_char1 found #{_char} in #{line}" if line =~ /_char/
end
check_char1(line, '"')
def check_char2(line, _char)
puts "check_char2 found #{_char.inspect} in #{line}" if line =~ _char
end
check_char2(line, /"/)
...and can it be made to work using line =~ /_char/? (How should the double-quote be passed to the method?)

If _char is just a string (i.e. no regex pattern matching needed) then just use String#include?
if line.include?(_char)
If you must use a regex for this then Regexp.escape is your friend:
if line =~ /#{Regexp.escape(_char)}/
if line =~ Regexp.new(Regexp.escape(_char))
and if you want _char to be treated like a regex (i.e. '.' matches anything) then drop the Regexp.escape:
if line =~ /#{_char}/
if line =~ Regexp.new(_char)

In check_char1, _char in /_char/ is treated as a literal, not a variable. You need /#{_char}/.
If _char were treated as variable how could one enter a literal in a regex that was the name of a variable, method or constant?

Related

Why this regular expression gets true in ruby?

I was started learning the regular expressions in ruby. In that I had one problem. The problem is the below regular expression does not work as expected.
/^[\s]*$/ -- This will match only if the input contains white spaces or the input contains empty.
For example,
str = "
abc
"
if str =~ /^[\s]*$/
puts "Condition is true"
else
puts "Condition is false"
end
My expectation is this condition will gets false. But it gets true. I don't know why ?
In sed or grep it will work as expected. But why it does not works in ruby.
The reason is that in Ruby regex, ^ and $ match the start/end of a line. Change to \A and \z and you will get a false result.
See this Ruby demo at Ideone. The /\A\s*\z/ will only match strings that are either empty or have whitespace symbols only.
As for \s, it is a synonym for [ \t\r\n\f], not just [ \t\n]. See this Ruby Character Class reference:
/\s/ - A whitespace character: /[ \t\r\n\f]/

Regexp for certain character to end of line

I have a string
"So on and so forth $5.99"
I would like to extract everything after the $ until the end of the line.
/$ finds the character $. How do I select the rest of the string? I know it's something \z but I can't get the syntax right.
In regexp $ represents the end of the line.
So in your case you need \$.*$ To include your escaped $ and everything (.*) up until the end of the line $.
No, /$ does not match that character. You need to escape it \ to match a literal.
string = "So on and so forth $5.99"
result = string.match(/\$(.*)$/)
puts result[1] #=> "5.99"
If you want to capture everything after the $, you'll want:
/\$(.*)\z/
See http://rubular.com/r/T4fR1SEl3j

Variables inside Regexp

Lets say I have the code:
str = "foobar"
print "Enter in the letters you would like to match: "
match = gets
# Pseudocode:
str =~ /[match]/
I don't want to match the whole string: match, I just want to match each of the letters, like:
str =~ /[aeiou]/
would yield the vowels.
How do I make it so I can match the letters the user inputs?
Try this:
match = gets.chomp # cut off that trailing \n
str =~ /[#{match}]/

Why does '\n' not work, and what does $/ mean?

Why doesn't this code work:
"hello \nworld".each_line(separator = '\n') {|s| p s}
while this works?
"hello \nworld".each_line(separator = $/) {|s| p s}
A 10 second google yielded this:
$/ is the input record separator, newline by default.
The first one doesn't work because you used single quotes. Backslash escape sequences are ignored in single quoted strings. Use double quotes instead:
"hello \nworld".each_line(separator = "\n") {|s| p s}
First, newline is the default. All you need is
"hello \nworld".each_line {|s| p s}
Secondly, single quotes behave differently than double quotes. '\n' means a literal backslash followed by the letter n, whereas "\n" means the newline character.
Last, the special variable $/ is the record separator which is "\n" by default, which is why you don't need to specify the separator in the above example.
Simple gsub! your string with valid "\n" new line character:
text = 'hello \nworld'
text.gsub!('\n', "\n")
After that \n character will act like newline character.

Ruby regex: ^ matches start of line even without m modifier?

Ruby 1.8.7. I'm using a regex with a ^ to match a pattern at the start of the string. The problem is that if the pattern is found at the start of any line in the string it still matches. This is the behaviour I would expect if I were using the 'm' modifier but I'm not:
$ irb
irb(main):001:0> str = "hello\ngoodbye"
=> "hello\ngoodbye"
irb(main):002:0> puts str
hello
goodbye
=> nil
irb(main):004:0> str =~ /^goodbye/
=> 6
What am I doing wrong here?
start of the line: ^
end of the line: $
start of the string: \A
end of the string: \z
Use \A instead of ^.
Ruby regex reference: http://www.zenspider.com/ruby/quickref.html#regexen
Your confusion is justified. In most regex flavors, ^ is equivalent to \A and $ is equivalent to \Z by default, and you have to set the "multiline" flag to make them take on their other meanings (i.e. line boundaries). In Ruby, ^ and $ always match at line boundaries.
To add to the confusion, Ruby has something it calls "multiline" mode, but it's really what everybody else calls "single-line" or "DOTALL" mode: it changes the meaning of the . metacharacter, allowing it to match line-separator characters (e.g. \r, \n) as well as all other characters.
"^" is the start of the line. To make what you want, you can split de string and test just the first line. But I think exist some better method.
str.split("\n")[0] =~ /^hello/

Resources