Ruby gsub doesn't escape single-quotes - ruby

I don't understand what is going on here. How should I feed gsub to get the string "Yaho\'o"?
>> "Yaho'o".gsub("Y", "\\Y")
=> "\\Yaho'o"
>> "Yaho'o".gsub("'", "\\'")
=> "Yahooo"

\' means $' which is everything after the match.
Escape the \ again and it works
"Yaho'o".gsub("'", "\\\\'")

"Yaho'o".gsub("'", "\\\\'")
Because you're escaping the escape character as well as escaping the single quote.

This will also do it, and it's a bit more readable:
def escape_single_quotes(str)
str.gsub(/'/) { |x| "\\#{x}" }
end
If you want to escape both a single-quote and a backslash, so that you can embed that string in a double-quoted ruby string, then the following will do that for you:
def escape_single_quotes_and_backslash(str)
str.gsub(/\\|'/) { |x| "\\#{x}" }
end

Related

Replacing ' by \' in Ruby [duplicate]

s = "#main= 'quotes'
s.gsub "'", "\\'" # => "#main= quotes'quotes"
This seems to be wrong, I expect to get "#main= \\'quotes\\'"
when I don't use escape char, then it works as expected.
s.gsub "'", "*" # => "#main= *quotes*"
So there must be something to do with escaping.
Using ruby 1.9.2p290
I need to replace single quotes with back-slash and a quote.
Even more inconsistencies:
"\\'".length # => 2
"\\*".length # => 2
# As expected
"'".gsub("'", "\\*").length # => 2
"'a'".gsub("'", "\\*") # => "\\*a\\*" (length==5)
# WTF next:
"'".gsub("'", "\\'").length # => 0
# Doubling the content?
"'a'".gsub("'", "\\'") # => "a'a" (length==3)
What is going on here?
You're getting tripped up by the specialness of \' inside a regular expression replacement string:
\0, \1, \2, ... \9, \&, \`, \', \+
Substitutes the value matched by the nth grouped subexpression, or by the entire match, pre- or postmatch, or the highest group.
So when you say "\\'", the double \\ becomes just a single backslash and the result is \' but that means "The string to the right of the last successful match." If you want to replace single quotes with escaped single quotes, you need to escape more to get past the specialness of \':
s.gsub("'", "\\\\'")
Or avoid the toothpicks and use the block form:
s.gsub("'") { |m| '\\' + m }
You would run into similar issues if you were trying to escape backticks, a plus sign, or even a single digit.
The overall lesson here is to prefer the block form of gsub for anything but the most trivial of substitutions.
s = "#main = 'quotes'
s.gsub "'", "\\\\'"
Since \it's \\equivalent if you want to get a double backslash you have to put four of ones.
You need to escape the \ as well:
s.gsub "'", "\\\\'"
Outputs
"#main= \\'quotes\\'"
A good explanation found on an outside forum:
The key point to understand IMHO is that a backslash is special in
replacement strings. So, whenever one wants to have a literal
backslash in a replacement string one needs to escape it and hence
have [two] backslashes. Coincidentally a backslash is also special in a
string (even in a single quoted string). So you need two levels of
escaping, makes 2 * 2 = 4 backslashes on the screen for one literal
replacement backslash.
source

Ruby Filter gsub replace \\n

I want to replace '\\n' with '\n'
i am using the gsub method but cannot replace
ruby
{
code => "#mystring=event.get('stockLines');
#mystring=#mystring.gsub('\\\n', '\n');"
}
You need to use "\n" not '\n' in your gsub. The different quote marks behave differently.
Read more
In your case:
#mystring.gsub("\\n", "\n")
The essential difference between the two literal forms of strings (single or double quotes) is that double quotes allow for escape sequences while single quotes do not!
Escaping of the backslash can be a bit weird.
For a regular Ruby script the code would be:
#mystring = event.get('stockLines').gsub('\\\\\n', '\n')
It seems like in logstash config the code is also in a string, so it needs to be escaped once more, i.e.:
ruby
{
code => "#mystring = event.get('stockLines').gsub('\\\\\\\\\\n', '\\n');"
}

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.

Ruby: escape escape sequence?

There is a string:
str = "foo\nbar"
How can I escape it to:
'foo\nbar'
?
I noticed "#{str}" doesn't work.
str.inspect Should do it for you
Add another \:
"foo\\nbar" == 'foo\nbar' #=> true
Single-quoted strings do not have interpolation, so #{str} does nothing special in them.

How to add a single backslash character to a string in Ruby?

I want to insert backslash before apostrophe in "children's world" string. Is there a easy way to do it?
irb(main):035:0> s = "children's world"
=> "children's world"
irb(main):036:0> s.gsub('\'', '\\\'')
=> "childrens worlds world"
Answer
You need some extra backslashes:
>> puts "children's world".gsub("'", '\\\\\'')
children\'s world
or slightly more concisely (since you don't need to escape the ' in a double-quoted string):
>> puts "children's world".gsub("'", "\\\\'")
children\'s world
or even more concisely:
>> puts "children's world".gsub("'") { "\\'" }
children\'s world
Explanation
Your '\\\'' generates \' as a string:
>> puts '\\\''
\'
and \' is a special replacement pattern in Ruby. From ruby-doc.org:
you may refer to some special match variables using these combinations ... \' corresponds to $', which contains string after match
So the \' that gsub sees in the second argument is being interpreted as a special pattern (everything in the original string after the match) instead of as a literal \'.
So what you want gsub to see is actually \\', which can be produced by '\\\\\'' or "\\\\'".
Or, if you use the block form of gsub (gsub("xxx") { "yyy" }) then Ruby takes the replacement string "yyy" literally without trying to apply replacement patterns.
Note: If you have to create a replacement string with a lot of \s you could take advantage of the fact that when you use /.../ (or %r{...}) you don't have to double-escape the backslashes:
>> puts "children's world".gsub("'", /\\'/.source)
children\'s world
Or you could use a single-quoted heredoc: (using <<'STR' instead of just <<STR)
>> puts "children's world".gsub("'", <<'STR'.strip)
\\'
STR
children\'s world
>> puts s.gsub("'", "\\\\'")
children\'s world
Your problem is that the string "\'" is meaningful to gsub in a replacement string. In order to make it work the way you want, you have to use the block form.
s.gsub("'") {"\\'"}

Resources