What is the most elegant way in Ruby to remove a p

2020-06-01 07:25发布

问题:

I would like to take out a parameter from a URL by its name without knowing which parameter it is, and reassemble the URL again.

I guess it is not that hard to write something on my own using CGI or URI, but I imagine such functionality exists already. Any suggestions?

In:

http://example.com/path?param1=one&param2=2&param3=something3

Out:

http://example.com/path?param2=2&param3=something3

回答1:

The addressable gem will do this nicely; please see the superior answer by The Tin Man. But if you want to roll your own, here's how. The only claim this code has to elegance is that it hides the ugly in a method:

#!/usr/bin/ruby1.8

def reject_param(url, param_to_reject)
  # Regex from RFC3986
  url_regex = %r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$"
  raise "Not a url: #{url}" unless url =~ url_regex
  scheme_plus_punctuation = $1
  authority_with_punctuation = $3
  path = $5
  query = $7
  fragment = $9
  query = query.split('&').reject do |param|
    param_name = param.split(/[=;]/).first
    param_name == param_to_reject
  end.join('&')
  [scheme_plus_punctuation, authority_with_punctuation, path, '?', query, fragment].join
end   

url = "http://example.com/path?param1=one&param2=2&param3=something3"
p url
p reject_param(url, 'param2')

# => "http://example.com/path?param1=one&param2=2&param3=something3"
# => "http://example.com/path?param1=one&param3=something3"


回答2:

I prefer to use:

require 'addressable/uri'

uri = Addressable::URI.parse('http://example.com/path?param1=one&param2=2&param3=something3')

params = uri.query_values #=> {"param1"=>"one", "param2"=>"2", "param3"=>"something3"}
params.delete('param1') #=> "one"
uri.query_values = params #=> {"param2"=>"2", "param3"=>"something3"}

uri.to_s #=> "http://example.com/path?param2=2&param3=something3"


回答3:

Maybe a little off-topic, but for anyone who's attempting to do this in the context of a rails app you can simply do:

url_for(params.except(:name_of_param_to_delete))

N.B. Tested in rails v2.3.9.



回答4:

If you don't want to include an extra Gem and if you don't want nasty Regex, here's my prefered way:

require 'cgi'
require 'uri'

url = "http://example.com/path?param1=one&param2=2&param3=something3"

uri = URI(url) #=> #<URI::HTTP:0x007fbe25141a78 URL:http://example.com/path?param1=one&param2=2&param3=something3>
params = Rack::Utils.parse_nested_query(uri.query || "") #=> {"param1"=>["one"], "param2"=>["2"], "param3"=>["something3"]}
params.delete('param1') #=> ["one"]
uri.query = URI.encode_www_form(params) #=> "param2=2&param3=something3"

uri.to_s #=> "http://example.com/path?param2=2&param3=something3"

Note, choose wisely:

CGI.parse('a=b&a=c') #=> {"a"=>["b", "c"]}
Rack::Utils.parse_nested_query('a=b&a=c') #=> {"a"=>"c"}

And:

URI.encode_www_form({ a: :b, c: { d: 2 }}) #=> "a=b&c=%7B%3Ad%3D%3E2%7D"
{ a: :b, c: { d: 2 }}.to_query #=> "a=b&c%5Bd%5D=2"


回答5:

I came up with something like this

 def uri_remove_param(uri, params = nil)
   return uri unless params
   params = Array(params)
   uri_parsed = URI.parse(uri)
   return uri unless uri_parsed.query
   escaped = uri_parsed.query.grep(/&amp;/).size > 0
   new_params = uri_parsed.query.gsub(/&amp;/, '&').split('&').reject { |q| params.include?(q.split('=').first) }
   uri = uri.split('?').first
   amp = escaped ? '&amp;' : '&'
   "#{uri}?#{new_params.join(amp)}"
 end


回答6:

One line should be enough:

url.sub(/\?param_to_remove=[^&]*/, '?').sub(/\&param_to_remove=[^&]*/, '').sub(/\?$/,'')


标签: ruby url parsing