How do I parse a quoted string inside another string? - ruby

I want to extract the quoted substrings from inside a string. This is an example:
string = 'aaaa' + string_var_x + 'bbbb' + string_var_y
The output after parsing should be:
["'aaaa'", "'bbbb'"]
The initial solution was to string.scan /'\w'/ which is almost ok.
Still I can't get it working on more complex string, as it's implied that inside '...' there can be any kind of characters (including numbers, and !##$%^&*() whatever).
Any ideas?
I wonder if there's some way to make /'.*'/ working, but make it less greedy?

Lazy should fix this:
/'.*?'/
Another possibility is to use this:
/'[^']*'/

An alternate way to do it is:
>> %{string = 'aaaa' + string_var_x + 'bbbb' + string_var_y}.scan(/'[^'].+?'/)
#=> ["'aaaa'", "'bbbb'"]
String.scan gets overlooked a lot.

Related

Change string to hash with ruby

I have ugly string that looks like this:
"\"New\"=>\"0\""
Which will be the best way to converting it into hash object?
Problem with "\"New\"=>\"0\"" is it does not look like a Hash. So first step should be to manipulate it to look like a Hash:
"{" + a + "}"
# => "{\"New\"=>\"0\"}"
Now once you have a hash looking string you can convert it into Hash like this:
eval "{" + a + "}"
# => {"New"=>"0"}
However there is still one issue, eval is not safe and inadvisable to use. So lets manipulate the string further to make it look json-like and use JSON.parse:
require `json`
JSON.parse ("{" + a + "}").gsub("=>",":")
# => {"New"=>"0"}
How about JSON.parse(string.gsub("=>", ":"))
You can use regex to pull out the key and value. Then create Hash directly
Hash[*"\"New\"=>\"0\"".scan(/".*?"/)]
Hard to nail down the best way if you can't tell us exactly the general format of those strings. You may not even need the regex. eg
Hash[*"\"New\"=>\"0\"".split('"').values_at(1,3)]
Also works for "\"Rocket\"=>\"=>\""

Is there a more elegant way to pad a string in Ruby?

So I have a string called borrowed_book_bitmask and I want to pad this string with another string both on the left and right. The padding is defined in some class as a constant. So I have
borrowed_book_bitmask = Module1::Model1::BITMASK_PADDING + borrowed_book_bitmask + Module1::Model1::BITMASK_PADDING
This syntax is a bit clunky and inelegant. Is there a better, more succinct way to express the above?
Assume I can't change the variable name and constant name.
You can use the center method
a = "abc"
"abc.center(a.size + 4 * 2)
=> " abc "
borrowed_book_bitmask.gsub! /\A|\z/, Module1::Model1::BITMASK_PADDING
What do you mean by "pad"? Always adding the same strings on each side?
"#{Module1::Model1::BITMASK_PADDING}#{borrowed_book_bitmask}#{Module1::Model1::BITMASK_PADDING"}
What do you mean by "elegant"? Interpolation is vaguely more elegant than concatenation (and more performant IIRC, which I might not). If borrowed_book_bitmask is a method then you could embed this in a method, or use a decorator to encapsulate the functionality.
It seems to me that the inelegance comes from the repetition of the module parameter; I keep having to visually parse two long terms to check that they are the same.
pad = Module1::Model1::BITMASK_PADDING
borrowed_book_bitmask = pad + borrowed_book_bitmask + pad
...too obvious? Maybe that's only more elegant for me.

Simple Ruby Regex Question

I have a string in Ruby:
str = "<TAG1>Text 1<TAG1>Text 2"
I want to use gsub to get a string like this:
want = "<TAG2>Text 1</TAG2><TAG2>Text2</TAG2>"
In other words, I want to save everything in between a <TAG1> and EITHER: 1) the next occurrence of a "<", or 2) the end of the string.
The best regex i could come up with was:
regex = /<TAG1>(.*)(?:<|$)/
But the problem with this is that it'll just match the entire str, where what I want is both matches within str. (In other words, it seems like the end of string char ($) seems to have precedence over the "<" character--is there a way to flip it around?
/<TAG1>([^<]*)/ will match that. If there's no < it'll go all the way to the end of the string. Otherwise it will stop when it hits a <. Your problem is that . matches < as well. An alternative way would be to do /<TAG1>(.*?)(?:<|$)/, which makes the * non-greedy.

Ruby: Escaping special characters in a string

I am trying to write a method that is the same as mysqli_real_escape_string in PHP. It takes a string and escapes any 'dangerous' characters. I have looked for a method that will do this for me but I cannot find one. So I am trying to write one on my own.
This is what I have so far (I tested the pattern at Rubular.com and it worked):
# Finds the following characters and escapes them by preceding them with a backslash. Characters: ' " . * / \ -
def escape_characters_in_string(string)
pattern = %r{ (\'|\"|\.|\*|\/|\-|\\) }
string.gsub(pattern, '\\\0') # <-- Trying to take the currently found match and add a \ before it I have no idea how to do that).
end
And I am using start_string as the string I want to change, and correct_string as what I want start_string to turn into:
start_string = %("My" 'name' *is* -john- .doe. /ok?/ C:\\Drive)
correct_string = %(\"My\" \'name\' \*is\* \-john\- \.doe\. \/ok?\/ C:\\\\Drive)
Can somebody try and help me determine why I am not getting my desired output (correct_string) or tell me where I can find a method that does this, or even better tell me both? Thanks a lot!
Your pattern isn't defined correctly in your example. This is as close as I can get to your desired output.
Output
"\\\"My\\\" \\'name\\' \\*is\\* \\-john\\- \\.doe\\. \\/ok?\\/ C:\\\\Drive"
It's going to take some tweaking on your part to get it 100% but at least you can see your pattern in action now.
def self.escape_characters_in_string(string)
pattern = /(\'|\"|\.|\*|\/|\-|\\)/
string.gsub(pattern){|match|"\\" + match} # <-- Trying to take the currently found match and add a \ before it I have no idea how to do that).
end
I have changed above function like this:
def self.escape_characters_in_string(string)
pattern = /(\'|\"|\.|\*|\/|\-|\\|\)|\$|\+|\(|\^|\?|\!|\~|\`)/
string.gsub(pattern){|match|"\\" + match}
end
This is working great for regex
This should get you started:
print %("'*-.).gsub(/["'*.-]/){ |s| '\\' + s }
\"\'\*\-\.
Take a look at the ActiveRecord sanitization methods: http://api.rubyonrails.org/classes/ActiveRecord/Base.html#method-c-sanitize_sql_array
Take a look at escape_string / quote method in Mysql class here

Flatten an array of strings in Ruby

What's the best idiomatic (cleanest) way to convert an array of strings into a string, while keeping the enclosing quotes for each elements.
In other words, from this:
a = ["file 1.txt", "file 2.txt", "file 3.txt"]
I'd need to get this
"'file 1.txt' 'file 2.txt' 'file 3.txt'"
Single and double quotes could be interchanged here.
The best ways I know of is by using map and inject/reduce.
eg: a.map{|dir| "'" + dir + "'"}.join(' ')
eg2: a.reduce("'"){|acc, dir| acc += dir+"' "}
Performance could be improved by avoiding temp string creation (+ operator). That's not my main question though. Is there a cleaner more concise way to achieve the same result?
Shorter doesn't always mean simpler. Your first example was succinct, readable, and easily changeable, without being unnecessarily complex.
a.map { |s| "'#{s}'" }.join(' ')
Try out
"'#{a.join("' '")}'"
Or if golfing
?'+a*"' '"+?'
Try this:
"'" + a.join("' '") + "'"
"'"+a*"' '"+"'"
or
"'#{a*"' '"}'"
or
a.to_s[1...-1].gsub /",?/,"'"

Resources