Ruby Interpolation - ruby

Could someone explain why doing this:
%{#$"}
in irb produces the following?
=> "[\"enumerator.so\", \"enc/encdb.so\", \"enc/big5.so\", \"enc/cp949.so\", \"enc/emacs_mule.so\", \"enc/euc_jp.so\", \"enc/euc_kr.so\", \"enc/euc_tw.so\", \"enc/gb2312.so\", \"enc/gb18030.so\", \"enc/gbk.so\", \"enc/iso_8859_1.so\" ... ]
Thanks!

%{ ... } is a string literal. It's similar to "...".
%{a string} == "a string"
# => true
#{expr} inside those string literal is interpolation. An expression expr inside the substituted with the value of it. For global variable you can omit { and }.
"#{1 + 2}"
# => "3"
%{#$"} == $".to_s
# => true
$" is one of pre-defined variables: an array of loaded module names.

Related

How do I escape a variable when using it in a regular expression? [duplicate]

Is is possible to create/use a regular expression pattern in ruby that is based on the value of a variable name?
For instance, we all know we can do the following with Ruby strings:
str = "my string"
str2 = "This is #{str}" # => "This is my string"
I'd like to do the same thing with regular expressions:
var = "Value"
str = "a test Value"
str.gsub( /#{var}/, 'foo' ) # => "a test foo"
Obviously that doesn't work as listed, I only put it there as an example to show what I'd like to do. I need to regexp match based on the value of a variable's content.
The code you think doesn't work, does:
var = "Value"
str = "a test Value"
p str.gsub( /#{var}/, 'foo' ) # => "a test foo"
Things get more interesting if var can contain regular expression meta-characters. If it does and you want those matacharacters to do what they usually do in a regular expression, then the same gsub will work:
var = "Value|a|test"
str = "a test Value"
str.gsub( /#{var}/, 'foo' ) # => "foo foo foo"
However, if your search string contains metacharacters and you do not want them interpreted as metacharacters, then use Regexp.escape like this:
var = "*This*"
str = "*This* is a string"
p str.gsub( /#{Regexp.escape(var)}/, 'foo' )
# => "foo is a string"
Or just give gsub a string instead of a regular expression. In MRI >= 1.8.7, gsub will treat a string replacement argument as a plain string, not a regular expression:
var = "*This*"
str = "*This* is a string"
p str.gsub(var, 'foo' ) # => "foo is a string"
(It used to be that a string replacement argument to gsub was automatically converted to a regular expression. I know it was that way in 1.6. I don't recall which version introduced the change).
As noted in other answers, you can use Regexp.new as an alternative to interpolation:
var = "*This*"
str = "*This* is a string"
p str.gsub(Regexp.new(Regexp.escape(var)), 'foo' )
# => "foo is a string"
It works, but you need to use gsub! or assign the return to another variable
var = "Value"
str = "a test Value"
str.gsub!( /#{var}/, 'foo' ) # Or this: new_str = str.gsub( /#{var}/, 'foo' )
puts str
Yes
str.gsub Regexp.new(var), 'foo'
You can use regular expressions through variables in ruby:
var = /Value/
str = "a test Value"
str.gsub( /#{var}/, 'foo' )
str.gsub( Regexp.new("#{var}"), 'foo' )

Ruby: Calling variable from array?

How do I call a variable from an array? Trying to make this:
hello_world = "Hey"
array = [ '#{hello_world} ho' ]
array.each do |a|
puts a
end
say ["Hey ho"] instead of ["\#{hello_world} ho"].
Do as below -
hello_world = "Hey"
array = [ "#{hello_world} ho" ]
array # => ["Hey ho"]
array.each do |a|
p a
end
# >> "Hey ho"
Single-quoted strings disabling interpolation, but double-quote strings allow interpolation.
Remember - Interpolation may be disabled by escaping the “#” character or using single-quote strings:
'#{1 + 1}' #=> "\#{1 + 1}"

How do you strip substrings in ruby?

I'd like to replace/duplicate a substring, between two delimeters -- e.g.,:
"This is (the string) I want to replace"
I'd like to strip out everything between the characters ( and ), and set that substr to a variable -- is there a built in function to do this?
I would just do:
my_string = "This is (the string) I want to replace"
p my_string.split(/[()]/) #=> ["This is ", "the string", " I want to replace"]
p my_string.split(/[()]/)[1] #=> "the string"
Here are two more ways to do it:
/\((?<inside_parenthesis>.*?)\)/ =~ my_string
p inside_parenthesis #=> "the string"
my_new_var = my_string[/\((.*?)\)/,1]
p my_new_var #=> "the string"
Edit - Examples to explain the last method:
my_string = 'hello there'
capture = /h(e)(ll)o/
p my_string[capture] #=> "hello"
p my_string[capture, 1] #=> "e"
p my_string[capture, 2] #=> "ll"
var = "This is (the string) I want to replace"[/(?<=\()[^)]*(?=\))/]
var # => "the string"
str = "This is (the string) I want to replace"
str.match(/\((.*)\)/)
some_var = $1 # => "the string"
As I understand, you want to remove or replace a substring as well as set a variable equal to that substring (sans the parentheses). There are many ways to do this, some of which are slight variants of the other answers. Here's another way that also allows for the possibility of multiple substrings within parentheses, picking up from #sawa's comments:
def doit(str, repl)
vars = []
str.gsub(/\(.*?\)/) {|m| vars << m[1..-2]; repl}, vars
end
new_str, vars = doit("This is (the string) I want to replace", '')
new_str # => => "This is I want to replace"
vars # => ["the string"]
new_str, vars = doit("This is (the string) I (really) want (to replace)", '')
new_str # => "This is I want"
vars # => ["the string", "really, "to replace"]
new_str, vars = doit("This (short) string is a () keeper", "hot dang")
new_str # => "This hot dang string is a hot dang keeper"
vars # => ["short", ""]
In the regex, the ? in .*? makes .* "lazy". gsub passes each match m to the block; the block strips the parens and adds it to vars, then returns the replacement string. This regex also works:
/\([^\(]*\)/

How to delete specific characters from a string in Ruby?

I have several strings that look like this:
"((String1))"
They are all different lengths. How could I remove the parentheses from all these strings in a loop?
Do as below using String#tr :
"((String1))".tr('()', '')
# => "String1"
If you just want to remove the first two characters and the last two, then you can use negative indexes on the string:
s = "((String1))"
s = s[2...-2]
p s # => "String1"
If you want to remove all parentheses from the string you can use the delete method on the string class:
s = "((String1))"
s.delete! '()'
p s # => "String1"
For those coming across this and looking for performance, it looks like #delete and #tr are about the same in speed and 2-4x faster than gsub.
text = "Here is a string with / some forwa/rd slashes"
tr = Benchmark.measure { 10000.times { text.tr('/', '') } }
# tr.total => 0.01
delete = Benchmark.measure { 10000.times { text.delete('/') } }
# delete.total => 0.01
gsub = Benchmark.measure { 10000.times { text.gsub('/', '') } }
# gsub.total => 0.02 - 0.04
Using String#gsub with regular expression:
"((String1))".gsub(/^\(+|\)+$/, '')
# => "String1"
"(((((( parentheses )))".gsub(/^\(+|\)+$/, '')
# => " parentheses "
This will remove surrounding parentheses only.
"(((((( This (is) string )))".gsub(/^\(+|\)+$/, '')
# => " This (is) string "
Here is an even shorter way of achieving this:
1) using Negative character class pattern matching
irb(main)> "((String1))"[/[^()]+/]
=> "String1"
^ - Matches anything NOT in the character class. Inside the charachter class, we have ( and )
Or with global substitution "AKA: gsub" like others have mentioned.
irb(main)> "((String1))".gsub(/[)(]/, '')
=> "String1"
Use String#delete:
"((String1))".delete "()"
=> "String1"

Check for a substring at the end of string

Let's say I have two strings:
"This-Test has a "
"This has a-Test"
How do I match the "Test" at the end of string and only get the second as a result and not the first string. I am using include? but it will match all occurrences and not just the ones where the substring occurs at the end of string.
You can do this very simply using end_with?, e.g.
"Test something Test".end_with? 'Test'
Or, you can use a regex that matches the end of the string:
/Test$/ === "Test something Test"
"This-Test has a ".end_with?("Test") # => false
"This has a-Test".end_with?("Test") # => true
Oh, the possibilities are many...
Let's say we have two strings, a = "This-Test has a" and b = "This has a-Test.
Because you want to match any string that ends exactly in "Test", a good RegEx would be /Test$/ which means "capital T, followed by e, then s, then t, then the end of the line ($)".
Ruby has the =~ operator which performs a RegEx match against a string (or string-like object):
a =~ /Test$/ # => nil (because the string does not match)
b =~ /Test$/ # => 11 (as in one match, starting at character 11)
You could also use String#match:
a.match(/Test$/) # => nil (because the string does not match)
b.match(/Test$/) # => a MatchData object (indicating at least one hit)
Or you could use String#scan:
a.scan(/Test$/) # => [] (because there are no matches)
b.scan(/Test$/) # => ['Test'] (which is the matching part of the string)
Or you could just use ===:
/Test$/ === a # => false (because there are no matches)
/Test$/ === b # => true (because there was a match)
Or you can use String#end_with?:
a.end_with?('Test') # => false
b.end_with?('Test') # => true
...or one of several other methods. Take your pick.
You can use the regex /Test$/ to test:
"This-Test has a " =~ /Test$/
#=> nil
"This has a-Test" =~ /Test$/
#=> 11
You can use a range:
"Your string"[-4..-1] == "Test"
You can use a regex:
"Your string " =~ /Test$/
String's [] makes it nice and easy and clean:
"This-Test has a "[/Test$/] # => nil
"This has a-Test"[/Test$/] # => "Test"
If you need case-insensitive:
"This-Test has a "[/test$/i] # => nil
"This has a-Test"[/test$/i] # => "Test"
If you want true/false:
str = "This-Test has a "
!!str[/Test$/] # => false
str = "This has a-Test"
!!str[/Test$/] # => true

Resources