I have a code that looks like following
value = +"#{x}/part"
value << "/part2"
I understand that value would contain something like valueOfX/part/part2, but I don't understand why there is + in front of the string. I tried searching for it, but search engines are not very good at understanding what "plus in front of a string ruby" means. I also tried to run this in online ruby repl with no difference when + is added or not added.
So question is why may it be useful to have + like this?
If the string is frozen, then return duplicated mutable string.
If the string is not frozen, then return the string itself.
source: https://ruby-doc.org/core/String.html#method-i-2B-40
So in your case, since your string is not frozen, your code is equivalent to:
value = "#{x}/part"
EDIT:
As explained by #stefan in the comments, in Ruby 2.x, interpolated string were frozen with frozen_string_literal: true. So value = +"#{x}/part" is not equivalent to value = "#{x}/part". It's not the case anymore with Ruby 3.
I have a string "990822". I want to know if the string starts with "99".
I could achieve this by getting the first two characters of the string, then check if this is equal to "99". How do I get the first two characters from a string?
You can use String#start_with?:
"990822".start_with?("99") #=> true
Consider using the method start_with?.
s = "990822"
=> "990822"
s.start_with? "99"
=> true
You can use a range to access string:
"990822"[0...2]
# => "99"
See the String docs
To get the first two characters, the most straightforward way is:
"990822"[0, 2] # => "99"
Using a range inside the method [] is both not straightforward and also creates a range object that is immediately thrown out, which is a waste.
However, the whole question is actually an XY-question.
Does anyone know a way to directly use a MatchData object containing named captures as the input to a String template formatting operation (%)? When I attempt to do so, I get a "positional args mixed with named args" error.
s = "One-Two-Three"
re = /(?<first>.*?)-(?<second>.*?)-(?<third>.*)/
puts "%{second}" % s.match(re)
I found other ways to achieve the functional objective (ie by creating an array of the captures in the desired order and using positional templating), but the code is comparatively klunky.
Try this:
s = "One-Two-Three"
re = /(?<first>.*?)-(?<second>.*?)-(?<third>.*)/
match = s.match(re)
[match.names.map(&:to_sym), match.captures].transpose.to_h
# => {:first=>"One", :second=>"Two", :third=>"Three"}
What about using string interpolation directly:
puts "#{s.match(re)['second']}"
For ruby < 2.0 you want to use Hash[]:
m = s.match re
Hash[m.names.map(&:to_sym).zip m.captures]
#=> {:first=>"One", :second=>"Two", :third=>"Three"}
I'm working on 2 cases:
assume I have those var:
a = "hello"
b = "hello-SP"
c = "not_hello"
Any partial matches
I want to accept any string that has the variable a inside, so b and c would match.
Patterned match
I want to match a string that has a inside, followed by '-', so b would match, c does not.
I am having problem, because I always used the syntax /expression/ to define Regexp, so how dynamically define an RegExp on Ruby?
You can use the same syntax to use variables in a regex, so:
reg1 = /#{a}/
would match on anything that contains the value of the a variable (at the time the expression is created!) and
reg2 = /#{a}-/
would do the same, plus a hyphen, so hello- in your example.
Edit: As Wayne Conrad points out, if a contains "any characters that would have special meaning in a regular expression," you need to escape them. Example:
a = ".com"
b = Regexp.new(Regexp.escape(a))
"blah.com" =~ b
Late to comment but I wasn't able to find what I was looking for.The above mentioned answers didn't help me.Hope it help someone new to ruby who just wants a quick fix.
Ruby Code:
st = "BJ's Restaurant & Brewery"
#take the string you want to match into a variable
m = (/BJ\'s/i).match(string) #(/"your regular expression"/.match(string))
# m has the match #<MatchData "BJ's">
m.to_s
# this will display the match
=> "BJ's"
I would like to convert the following string into an array/nested array:
str = "[[this, is],[a, nested],[array]]"
newarray = # this is what I need help with!
newarray.inspect # => [['this','is'],['a','nested'],['array']]
You'll get what you want with YAML.
But there is a little problem with your string. YAML expects that there's a space behind the comma. So we need this
str = "[[this, is], [a, nested], [array]]"
Code:
require 'yaml'
str = "[[this, is],[a, nested],[array]]"
### transform your string in a valid YAML-String
str.gsub!(/(\,)(\S)/, "\\1 \\2")
YAML::load(str)
# => [["this", "is"], ["a", "nested"], ["array"]]
You could also treat it as almost-JSON. If the strings really are only letters, like in your example, then this will work:
JSON.parse(yourarray.gsub(/([a-z]+)/,'"\1"'))
If they could have arbitrary characters (other than [ ] , ), you'd need a little more:
JSON.parse("[[this, is],[a, nested],[array]]".gsub(/, /,",").gsub(/([^\[\]\,]+)/,'"\1"'))
For a laugh:
ary = eval("[[this, is],[a, nested],[array]]".gsub(/(\w+?)/, "'\\1'") )
=> [["this", "is"], ["a", "nested"], ["array"]]
Disclaimer: You definitely shouldn't do this as eval is a terrible idea, but it is fast and has the useful side effect of throwing an exception if your nested arrays aren't valid
Looks like a basic parsing task. Generally the approach you are going to want to take is to create a recursive function with the following general algorithm
base case (input doesn't begin with '[') return the input
recursive case:
split the input on ',' (you will need to find commas only at this level)
for each sub string call this method again with the sub string
return array containing the results from this recursive method
The only slighlty tricky part here is splitting the input on a single ','. You could write a separate function for this that would scan through the string and keep a count of the openbrackets - closedbrakets seen so far. Then only split on commas when the count is equal to zero.
Make a recursive function that takes the string and an integer offset, and "reads" out an array. That is, have it return an array or string (that it has read) and an integer offset pointing after the array. For example:
s = "[[this, is],[a, nested],[array]]"
yourFunc(s, 1) # returns ['this', 'is'] and 11.
yourFunc(s, 2) # returns 'this' and 6.
Then you can call it with another function that provides an offset of 0, and makes sure that the finishing offset is the length of the string.