I have a string that is URL encoded:
a = "%5B%22552A8619-6ECA-4A95-A798-C1E2CE75BFFF%22%2C%2264c19b5b2d0257ddb382dbd3660de3fd%22%2C%22share%22%5D"
If I URL decode this string then it will look like:
"[\"552A8619-6ECA-4A95-A798-C1E2CE75BFFF\",\"64c19b5b2d0257ddb382dbd3660de3fd\",\"share\"]"
From this string I want to get this array:
["552A8619-6ECA-4A95-A798-C1E2CE75BFFF","64c19b5b2d0257ddb382dbd3660de3fd","share"]
How to do that without nasty string replacements?
the_given_string.scan(/"(.*?)"/).flatten
The string is an array encoded using JSON:
require 'cgi'
require 'json'
a = "%5B%22552A8619-6ECA-4A95-A798-C1E2CE75BFFF%22%2C%2264c19b5b2d0257ddb382dbd3660de3fd%22%2C%22share%22%5D"
JSON[CGI::unescape(a)]
[
[0] "552A8619-6ECA-4A95-A798-C1E2CE75BFFF",
[1] "64c19b5b2d0257ddb382dbd3660de3fd",
[2] "share"
]
JSON[CGI::unescape(a)].last will return "share", putting you home free.
CGI::escape is used to remove the encoding, which turns it back to a "normal" JSON-encoded array.
JSON[] (AKA JSON.parse) converts it from the JSON notation back to a Ruby array.
You could delete characters and split, or evaluate it:
"[\"A798-C1E2CE75BFFF\",\"643fd\",\"share\"]".delete('\"[]').split(',')
# => ["A798-C1E2CE75BFFF", "643fd", "share"]
eval "[\"A798-C1E2CE75BFFF\",\"643fd\",\"share\"]"
# => ["A798-C1E2CE75BFFF", "643fd", "share"]
You could eval the string:
require 'cgi'
a = "%5B%22552A8619-6ECA-4A95-A798-C1E2CE75BFFF%22%2C%2264c19b5b2d0257ddb382dbd3660de3fd%22%2C%22share%22%5D"
x = eval( CGI.unescape(a))
p x #["552A8619-6ECA-4A95-A798-C1E2CE75BFFF", "64c19b5b2d0257ddb382dbd3660de3fd", "share"]
But eval is evil.
You could use , what you call nasty string replacement:
p CGI.unescape(a).gsub(/\A\["|"\]\Z/,'').split(/","/)
Or you could try JSON:
require 'cgi'
require 'json'
a = "%5B%22552A8619-6ECA-4A95-A798-C1E2CE75BFFF%22%2C%2264c19b5b2d0257ddb382dbd3660de3fd%22%2C%22share%22%5D"
x = JSON.load( CGI.unescape(a))
Related
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}
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}")
I have a string stored in a database like so:
images = '[{"id":1,"type":"Image","image_id":"asdf123"},{"id":2,"type":"Image","image_id":"asdf456"},{"id":3,"type":"Image","image_id":"asdf890"}]'
And would like to convert it to an array so I can do something like:
images.each do |image|
puts image.image_id
end
Is it really just a matter of removing the outer square brackets and then following the procedure from this question Converting a Ruby String into an array or is there a more direct/elegant method?
That format is called JavaScript Object Notation (JSON) and can be parsed by a builtin Ruby library:
require 'json'
images_str = '[{"id":1,"type":"Image","image_id":"asdf123"},{"id":2,"type":"Image","image_id":"asdf456"},{"id":3,"type":"Image","image_id":"asdf890"}]'
images = JSON.parse(images_str)
images.size # => 3
images[0].class # => Hash
images[0]['image_id'] # => "asdf123"
images.each { |x| puts "#{x['id']}: #{x['image_id']}" }
# 1: asdf123
# 2: asdf456
# 3: asdf890
I have tried:
require 'net/http'
require 'json'
require 'pp'
require 'uri'
url = "http://xyz.com"
resp = Net::HTTP.get_response(URI.parse(url))
buffer = resp.body
result = JSON.parse(buffer)
#result.to_hash
#pp result
puts result
And got the output as:
{"id"=>"ABC", "account_id"=>"123", "first_name"=> "PEUS" }
in JSON format but I only need the value of id to be printed as ABC.
Your incoming string in JSON would look like:
{"id":"ABC","account_id":"123","first_name":"PEUS"}
After parsing with JSON it's the hash:
{"id"=>"ABC", "account_id"=>"123", "first_name"=> "PEUS" }
So, I'd use:
hash = {"id"=>"ABC", "account_id"=>"123", "first_name"=> "PEUS" }
hash['id'] # => "ABC"
Here's a more compact version:
require 'json'
json = '{"id":"ABC","account_id":"123","first_name":"PEUS"}'
hash = JSON[json]
hash['id'] # => "ABC"
Note I'm using JSON[json]. The JSON [] class method is smart enough to sense what the parameter being passed in is. If it's a string it'll parse the string. If it's an Array or Hash it'll serialize it. I find that handy because it allows me to write JSON[...] instead of having to remember whether I'm parsing or using to_json or something. Using it is an example of the first virtue of programmers.
In Ruby, I have:
require 'uri'
foo = "et tu, brutus?"
bar = URI.encode(foo) # => "et%20tu,%20brutus?"
I'm trying to get bar to equal "et%20tu,%20brutus%3f" ("?" replaced with "%3F") When I try to add this:
bar["?"] = "%3f"
the "?" matches everything, and I get
=> "%3f"
I've tried
bar["\?"]
bar['?']
bar["/[?]"]
bar["/[\?]"]
And a few other things, none of which work.
require 'cgi' and call CGI.escape
There is only one good way to do this right now in Ruby:
require "addressable/uri"
Addressable::URI.encode_component(
"et tu, brutus?",
Addressable::URI::CharacterClasses::PATH
)
# => "et%20tu,%20brutus%3F"
But if you're doing stuff with URIs you should really be using Addressable anyways.
sudo gem install addressable
Here's a sample irb session:
irb(main):001:0> x = "geo?"
=> "geo?"
irb(main):002:0> x.sub!("?","a")
=> "geoa"
irb(main):003:0>
However, sub will only replace the first character. If you want to replace all the question marks in a string, use the gsub method like this:
str.gsub!("?","replacement")
If you know which characters you accept, you can remove those that don't match.
accepted_chars = 'A-z0-9\s,'
foo = "et tu, brutus?"
bar = foo.gsub(/[^#{accepted_chars}]/, '')
URI.escape accepts the optional parameter to tell which characters you want to escape. It overrides defaults so you'll have to call it twice.
> URI.escape URI.escape("et tu, brutus?"), "?"
=> "et%20tu,%20brutus%3F"