Я хотел бы извлечь параметр из URL по его имени, не зная, какой это параметр, и снова собрать URL.
Полагаю, что написать что-то самостоятельно с использованием CGI или URI не так сложно, но я думаю, что такая функциональность уже существует. Есть предложения?
В:
http://example.com/path?param1=one¶m2=2¶m3=something3
Из:
http://example.com/path?param2=2¶m3=something3
Я предпочитаю использовать:
require 'addressable/uri' uri = Addressable::URI.parse('http://example.com/path?param1=one¶m2=2¶m3=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¶m3=something3"
Может быть, немного не по теме, но для любого, кто пытается сделать это в контексте приложения rails, вы можете просто сделать:
url_for(params.except(:name_of_param_to_delete))
N.B. Проверено в рельсах v2.3.9.
Если вы не хотите включать дополнительный драгоценный камень и если вы не хотите отвратительного регулярного выражения, вот мой предпочтительный способ:
require 'cgi' require 'uri' url = "http://example.com/path?param1=one¶m2=2¶m3=something3" uri = URI(url) #=> #<URI::HTTP:0x007fbe25141a78 URL:http://example.com/path?param1=one¶m2=2¶m3=something3> params = CGI.parse(uri.query || "") #=> {"param1"=>["one"], "param2"=>["2"], "param3"=>["something3"]} params.delete('param1') #=> ["one"] uri.query = URI.encode_www_form(params) #=> "param2=2¶m3=something3" uri.to_s #=> "http://example.com/path?param2=2¶m3=something3"
гем адресуемый сделает это хорошо; пожалуйста, посмотрите превосходный ответ Жестянщик . Но если вы хотите свернуть свои собственные, вот как. Единственное требование, которое этот код имеет к элегантности, - то, что он скрывает уродливое в методе:
#!/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¶m2=2¶m3=something3" p url p reject_param(url, 'param2') # => "http://example.com/path?param1=one¶m2=2¶m3=something3" # => "http://example.com/path?param1=one¶m3=something3"
Я придумал что-то вроде этого
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(/&/).size > 0 new_params = uri_parsed.query.gsub(/&/, '&').split('&').reject { |q| params.include?(q.split('=').first) } uri = uri.split('?').first amp = escaped ? '&' : '&' "#{uri}?#{new_params.join(amp)}" end
Одной строки должно быть достаточно:
url.sub(/\?param_to_remove=[^&]*/, '?').sub(/\¶m_to_remove=[^&]*/, '').sub(/\?$/,'')