Ruby: eval with string interpolation - ruby

I don't understand, why eval works like this:
"123 #{456.to_s} 789" # => "123 456 789"
eval('123 #{456.to_s} 789') # => 123
How can I interpolate into a string inside eval?
Update:
Thank you, friends. It worked.
So if you have a string variable with #{} that you want to eval later, you should do it as explained below:
string = '123 #{456} 789'
eval("\"" + string + "\"")
# => 123 456 789
or
string = '123 #{456} 789'
eval('"' + string + '"')
# => 123 456 789

What's happening, is eval is evaluating the string as source code. When you use double quotes, the string is interpolated
eval '"123 #{456.to_s} 789"'
# => "123 456 789"
However when you use single quotes, there is no interpolation, hence the # starts a comment, and you get
123 #{456.to_s} 789
# => 123
The string interpolation happens before the eval call because it is the parameter to the method.
Also note the 456.to_s is unnecessary, you can just do #{456}.

You wanted:
eval('"123 #{456.to_s} 789"')
. . . hopefully you can see why?
The code passed to the interpretter from eval is exactly as if you had written it (into irb, or as part of a .rb file), so if you want an eval to output a string value, the string you evaluate must include the quotes that make the expression inside it a String.

Related

expr does not return the pattern if not at the beginning of the string

Using this version of bash:
GNU bash, version 4.1.2(1)-release (i386-redhat-linux-gnu)
How can I get expr to find my pattern within a string, if the pattern I'm looking for does not begin this string?
Example:
expr match "123 abc 456 def ghi789" '\([0-9]*\)' #returns 123 as expected
expr match "z 123 abc 456 def ghi789" '\([0-9]*\)' #returns nothing
In the second example, I would expect 123 to be returned.
Further analysis:
If I start from the end of the string by adding .* in my command, I get a weird result:
expr match "123 abc 456 def ghi789" '.*\([0-9]*\)' #returns nothing
expr match "123 abc 456 def ghi789" '.*\([0-9]\)' #returns 9 as expected
expr match "123 abc 456 def ghi789 z" '.*\([0-9]\)' #returns also 9
Here, it seems that the pattern can be found at the end of the string (so at the beginning of my search), and also if it's not at the end of the string. But it does not work if I add the * at the end of the regular expression.
In the other hand, the same does not apply if I start from the beginning of my string:
expr match "z 123 abc 456 def ghi789" '\([0-9]\)' #returns nothing
I think I must misunderstand something obvious, but I cannot find what.
Thank you for your help :)
Would
expr match "123 abc 456 def ghi789 z" '[^0-9]*\([0-9]*\)
do it? (Just added [0-9]* instead of .* at the beginning)
Like mentioned in the comments - the expression
expr match "123 abc 456 def ghi789 z" '^[^0-9]*\([0-9]*\)
would fit better, because the part ^[^0-9] can be read as "skip all characters which are not digits ([^0-9]) form begin (the ^as first character)"

Gsub causing part of string to be substituted

I want to replace all occurrences of a single quote (') with backslash single quote (\'). I tried doing this with gsub, but I'm getting partial string duplication:
a = "abc 'def' ghi"
a.gsub("'", "\\'")
# => "abc def' ghidef ghi ghi"
Can someone explain why this happens and what a solution to this is?
It happens because "\\'" has a special meaning when it occurs as the replacement argument of gsub, namely it means the post-match substring.
To do what you want, you can use a block:
a.gsub("'"){"\\'"}
# => "abc \\'def\\' ghi"
Notice that the backslash is escaped in the string inspection, so it appears as \\.
Your "\\'" actually represents a literal \' because of the backslash escaping the next backslash. And that literal \' in Ruby regex is actually a special variable that interpolates to the part of the string that follows the matched portion. So here's what's happening.
abc 'def' ghi
^
The caret points to the first match, '. Replace it with everything to its right, i.e. def' ghi.
abc def' ghidef' ghi
++++++++
Now find the next match:
abc def' ghidef' ghi
^
Once again, replace the ' with everything to its right, i.e. ghi.
abc def' ghidef ghi ghi
++++
It's possible you just need a higher dose of escaping:
a.gsub(/'/, "\\\\'" )
Result:
abc \'def\' ghi

Replacing escape quotes with just quotes in a string

So I'm having an issue replacing \" in a string.
My Objective:
Given a string, if there's an escaped quote in the string, replace it with just a quote
So for example:
"hello\"74" would be "hello"74"
simp"\"sons would be simp"sons
jump98" would be jump98"
I'm currently trying this: but obviously that doesn't work and messes everything up, any assistance would be awesome
str.replace "\\"", "\""
I guess you are being mistaken by how \ works. You can never define a string as
a = "hello"74"
Also escape character is used only while defining the variable its not part of the value. Eg:
a = "hello\"74"
# => "hello\"74"
puts a
# hello"74
However in-case my above assumption is incorrect following example should help you:
a = 'hello\"74'
# => "hello\\\"74"
puts a
# hello\"74
a.gsub!("\\","")
# => "hello\"74"
puts a
# hello"74
EDIT
The above gsub will replace all instances of \ however OP needs only to replace '" with ". Following should do the trick:
a.gsub!("\\\"","\"")
# => "hello\"74"
puts a
# hello"74
You can use gsub:
word = 'simp"\"sons';
print word.gsub(/\\"/, '"');
//=> simp""sons
I'm currently trying str.replace "\\"", "\"" but obviously that doesn't work and messes everything up, any assistance would be awesome
str.replace "\\"", "\"" doesn't work for two reasons:
It's the wrong method. String#replace replaces the entire string, you are looking for String#gsub.
"\\"" is incorrect: " starts the string, \\ is a backslash (correctly escaped) and " ends the string. The last " starts a new string.
You have to either escape the double quote:
puts "\\\"" #=> \"
Or use single quotes:
puts '\\"' #=> \"
Example:
content = <<-EOF
"hello\"74"
simp"\"sons
jump98"
EOF
puts content.gsub('\\"', '"')
Output:
"hello"74"
simp""sons
jump98"

Regex to match any character except a backslash

How can i say "all symbols except backslash" in Ruby character class?
/'[^\]*'/.match("'some string \ hello'") => should be nil
Variant with two backslashed doesn't work
/'[^\\]*'/.match("'some string \ hello'") => 'some string \ hello' BUT should be nil
Your problem is not with your regex; you got that right. Your problem is that your test string does not have a backslash in it. It has an escaped space, instead. Try this:
str = "'some string \\ hello'"
puts str #=> 'some string \ hello'
p /'[^\\]*'/.match(str) #=> nil
You need to escape the backslash:
[^\\]*
because backslash is the escape character in regular expressions, thus escaping the closing bracket here.
If you want to verify that the whole string contains non-backslash characters, then you need anchors:
^[^\\]*$
There's actually not a backslash in your string to match against. Try taking a look at just your input:
"'some string \ hello'".length # => 20
"a\ b".length # => 3
The "\ " in double quotes is being escaped into just a space:
irb(main):014:0> " "[0].to_i # => 32
irb(main):015:0> "\ "[0].to_i # => 32
irb(main):016:0> "\ ".size #=> 1
If you want to match no slash, you'll need two, like in your second example, which looks good to me:
/'[^\\]*'/.match("'some string \\ hello'") # => nil
This is relevant to Csharp.. but idk it might help you.
[^\\\\]*
four slashes instead of two.

How do I use string.tr to replace double quotes with single ones in Ruby?

How do I use string.tr to replace double quotes with single ones in Ruby?
'abc "def" ghi'.tr('"', "'") # => abc 'def' ghi
Besides tr, you can also use gsub
irb(main):001:0> 'abc "def" ghi'.gsub(/"/,"'")
=> "abc 'def' ghi"

Resources