Extract url params in ruby - ruby

I would like to extract parameters from url. I have following path pattern:
pattern = "/foo/:foo_id/bar/:bar_id"
And example url:
url = "/foo/1/bar/2"
I would like to get {foo_id: 1, bar_id: 2}. I tried to convert pattern into something like this:
"\/foo\/(?<foo_id>.*)\/bar\/(?<bar_id>.*)"
I failed on first step when I wanted to replace backslash in url:
formatted = pattern.gsub("/", "\/")
Do you know how to fix this gsub? Maybe you know better solution to do this.
EDIT:
It is plain Ruby. I am not using RoR.

As I said above, you only need to escape slashes in a Regexp literal, e.g. /foo\/bar/. When defining a Regexp from a string it's not necessary: Regexp.new("foo/bar") produces the same Regexp as /foo\/bar/.
As to your larger problem, here's how I'd solve it, which I'm guessing is pretty much how you'd been planning to solve it:
PATTERN_PART_MATCH = /:(\w+)/
PATTERN_PART_REPLACE = '(?<\1>.+?)'
def pattern_to_regexp(pattern)
expr = Regexp.escape(pattern) # just in case
.gsub(PATTERN_PART_MATCH, PATTERN_PART_REPLACE)
Regexp.new(expr)
end
pattern = "/foo/:foo_id/bar/:bar_id"
expr = pattern_to_regexp(pattern)
# => /\/foo\/(?<foo_id>.+?)\/bar\/(?<bar_id>.+?)/
str = "/foo/1/bar/2"
expr.match(str)
# => #<MatchData "/foo/1/bar/2" foo_id:"1" bar_id:"2">

Try this:
regex = /\/foo\/(?<foo_id>.*)\/bar\/(?<bar_id>.*)/i
matches = "/foo/1/bar/2".match(regex)
Hash[matches.names.zip(matches[1..-1])]
IRB output:
2.3.1 :032 > regex = /\/foo\/(?<foo_id>.*)\/bar\/(?<bar_id>.*)/i
=> /\/foo\/(?<foo_id>.*)\/bar\/(?<bar_id>.*)/i
2.3.1 :033 > matches = "/foo/1/bar/2".match(regex)
=> #<MatchData "/foo/1/bar/2" foo_id:"1" bar_id:"2">
2.3.1 :034 > Hash[matches.names.zip(matches[1..-1])]
=> {"foo_id"=>"1", "bar_id"=>"2"}
I'd advise reading this article on how Rack parses query params. The above works for your example you gave, but is not extensible for other params.
http://codefol.io/posts/How-Does-Rack-Parse-Query-Params-With-parse-nested-query

This might help you, the foo id and bar id will be dynamic.
require 'json'
#url to scan
url = "/foo/1/bar/2"
#scanning ids from url
id = url.scan(/\d/)
#gsub method to replacing values from url
url_with_id = url.gsub(url, "{foo_id: #{id[0]}, bar_id: #{id[1]}}")
#output
=> "{foo_id: 1, bar_id: 2}"
If you want to change string to hash
url_hash = eval(url_with_id)
=>{:foo_id=>1, :bar_id=>2}

Related

How to replace string in URL with captured regex pattern

I want to replace 'hoge' to 'foo' with regex. But the user's value is dynamic so I can't use str.gsub('hoge', 'foo').
str = '?user=hoge&tab=fuga'
What should I do?
Don't do this with a regular expression.
This is how to manipulate URIs using the existing wheels:
require 'uri'
str = 'http://example.com?user=hoge&tab=fuga'
uri = URI.parse(str)
query = URI.decode_www_form(uri.query).to_h # => {"user"=>"hoge", "tab"=>"fuga"}
query['user'] = 'foo'
uri.query = URI.encode_www_form(query)
uri.to_s # => "http://example.com?user=foo&tab=fuga"
Alternately:
require 'addressable'
uri = Addressable::URI.parse('http://example.com?tab=fuga&user=hoge')
query = uri.query_values # => {"tab"=>"fuga", "user"=>"hoge"}
query['user'] = 'foo'
uri.query_values = query
uri.to_s # => "http://example.com?tab=fuga&user=foo"
Note that in the examples the order of the parameters changed, but the code handled the difference without problems.
The reason you want to use URI or Addressable is because parameters and values have to be correctly encoded when they contain illegal characters. URI and Addressable know the rules and will follow them, whereas naive code assumes it's OK to not bother with encoding, causing broken URIs.
URI is part of the Ruby Standard Library, and Addressable is more full-featured. Take your pick.
You can try below regex
([?&]user=)([^&]+)
DEMO
You probably want to find out what the user query maps to first before using a .gsub to replace whatever value it is.
First, parse the URL string into an URI object using the URI module. And then, you can use the CGI query methods to get the key value pairs of the query params off the URI object using the CGI module. And finally, you can .gsub off the values in that hash.

Regular expression in ruby?

I have a URL like below.
/shows/the-ruby-book/meta-programming/?play=5b35a825-d372-4375-b2f0-f641a38067db"
I need to extract only the id of the play (i.e. 5b35a825-d372-4375-b2f0-f641a38067db) using regular expression. How can I do it?
I would not use a regexp to parse a url. I would use Ruby's libraries to handle URLs:
require 'uri'
url = '/shows/the-ruby-book/meta-programming/?play=5b35a825-d372-4375-b2f0-f641a38067db'
uri = URI.parse(url)
params = URI::decode_www_form(uri.query).to_h
params['play']
# => 5b35a825-d372-4375-b2f0-f641a38067db
You can do:
str = '/shows/the-ruby-book/meta-programming/?play=5b35a825-d372-4375-b2f0-f641a38067db'
match = str.match(/.*\?play=([^&]+)/)
puts match[1]
=> "5b35a825-d372-4375-b2f0-f641a38067db"
The regex /.*\?play=([^&]+)/ will match everything up until ?play=, and then capture anything that is not a & (the query string parameter separator)
A match will create a MatchData object, represented here by match variable, and captures will be indices of the object, hence your matched data is available at match[1].
url = '/shows/the-ruby-book/meta-programming/?play=5b35a825-d372-4375-b2f0-f641a38067db'
url.split("play=")[1] #=> "5b35a825-d372-4375-b2f0-f641a38067db"
Ruby's built-in URI class has everything needed to correctly parse, split and decode URLs:
require 'uri'
uri = URI.parse('/shows/the-ruby-book/meta-programming/?play=5b35a825-d372-4375-b2f0-f641a38067db')
URI::decode_www_form(uri.query).to_h['play'] # => "5b35a825-d372-4375-b2f0-f641a38067db"
If you're using an older Ruby that doesn't support to_h, use:
Hash[URI::decode_www_form(uri.query)]['play'] # => "5b35a825-d372-4375-b2f0-f641a38067db"
You should use URI, rather than try to split/extract using a regexp, because the query of a URI will be encoded if any values are not within the characters allowed by the spec. URI, or Addressable::URI, will decode those back to their original values for you.

How to insert variables in an url?

I have this code for send a request to an url, and I wanted to place on the url two variables :
talksList = open('http://yolo.com/?action=cp_list&id=#{variable1}&key=#{variable2}')
But when I insert my variables like this, it doesn't work. Can you help me ?
Thanks in advance.
As #YuHao said, you're trying to interpolate a variable into a non-interpreted string. But you have a bigger long-term problem.
Don't try to inject unencoded variables into a URL. While it will work, you run the risk of generating nonsensical URLs, which a browser would accept, but code won't. Instead, use the appropriate tools to modify the URL, which will maintain appropriate encoding for you.
Here's an example using URI:
require 'uri'
variable1 = 'foo'
variable2 = 'bar'
uri = URI.parse('http://yolo.com/?action=cp_list')
params = URI.decode_www_form(uri.query)
params << ['id', variable1]
params << ['key', variable2]
uri.query = URI.encode_www_form(params)
uri.to_s # => "http://yolo.com/?action=cp_list&id=foo&key=bar"
You can do the same thing using the Addressable gem, which is more full-featured:
require 'addressable/uri'
variable1 = 'foo'
variable2 = 'bar'
uri = Addressable::URI.parse('http://yolo.com/?action=cp_list')
params = uri.query_values
uri.query_values = params.merge('id' => variable1, 'key' => variable2)
uri.to_s # => "http://yolo.com/?action=cp_list&id=foo&key=bar"
That's because you are using strings with single quotes. In single quoted strings, nothing is replaced except \\ and \'.
Specifically, interpolation is only available in double quoted strings, try
talksList = open("http://yolo.com/?action=cp_list&id=#{variable1}&key=#{variable2}")

Extracting a part of a string in Ruby

I know this is an easy question, but I want to extract one part of a string with rails.
I would do this like Java, by knowing the beginning and end character of the string and extract it, but I want to do this by ruby way, that's why I need your help.
My string is:
STACK OVER AND FLOW
And I want the numerical values between quotation marks => 99999 and the value of the link => STACK OVER AND FLOW
How should I parse this string in ruby ?
Thanks.
If you need to parse html:
> require 'nokogiri'
> str = %q[STACK OVER AND FLOW]
> doc = Nokogiri.parse(str)
> link = doc.at('a')
> link.text
=> "STACK OVER AND FLOW"
> link['href'][/(\d+)/, 1]
=> "99999"
http://nokogiri.org/
This should work if you have only one link in string
str = %{STACK OVER AND FLOW }
num = str.match(/href=".*?'(\d*)'.*?/)[1].to_i
name = str.match(/>(.*?)</)[1].strip
Way to get both at a time:
str = "STACK OVER AND FLOW "
num, name = str.scan(/launchRemote\('(\d+)'[^>]+>\s*(.*?)\s*</).first
# => ["99999", "STACK OVER AND FLOW"]

ruby string splitting problem

i have this string:
"asdasda=asdaskdmasd&asmda=asdasmda&ACK=Success&asdmas=asdakmsd&asmda=adasda"
i want to get the value after between the ACK and the & symbol, the value between the ACK and the & symbol can be changed...
thanks
i want the solution in ruby.
require "cgi"
query_string = "asdasda=asdaskdmasd&asmda=asdasmda&ACK=Success&asmda=asdakmsd"
parsed_query_string = CGI.parse(query_string)
#=> { "asdasda" => ["asdaskdmasd"],
# "asmda" => ["asdasmda", "asdakmsd"],
# "ACK" => ["Success"] }
parsed_query_string["ACK"].first
#=> "Success"
If you also want to reconstruct the query string (especially together with the rest of a URL), I would recommend looking into the addressable gem.
require "addressable/uri"
# Note the leading '?'
query_string = "?asdasda=asdaskdmasd&asmda=asdasmda&ACK=Success&asmda=asdakmsd"
parsed_uri = Addressable::URI.parse(query_string)
parsed_uri.query_values["ACK"]
#=> "Success"
parsed_uri.query_values = parsed_uri.query_values.merge("ACK" => "Changed")
parsed_uri.to_s
#=> "?ACK=Changed&asdasda=asdaskdmasd&asmda=asdakmsd"
# Note how the order has changed and the duplicate key has been removed due to
# Addressable's built-in normalisation.
"asdasda=asdaskdmasd&asmda=asdasmda&ACK=Success&asdmas=asdakmsd&asmda=adasda"[/ACK=([^&]*)&/]
$1 # => 'Success'
A quick approach:
s = "asdasda=asdaskdmasd&asmda=asdasmda&ACK=Success&asdmas=asdakmsd&asmda=adasda"
s.gsub(/ACK[=\w]+&/,"ACK[changedValue]&")
#=> asdasda=asdaskdmasd&asmda=asdasmda&ACK[changedValue]&asdmas=asdakmsd&asmda=adasda
s = "asdasda=asdaskdmasd&asmda=asdasmda&ACK=Success&asdmas=asdakmsd&asmda=adasda"
m = s.match /.*ACK=(.*?)&/
puts m[1]
and just for fun without regexp:
Hash[s.split("&").map{|p| p.split("=")}]["ACK"]

Resources