0

I need to insert a string right after a certain substring pattern in a URL and replace whatever number was there previously.

/ei/sort.do?layoutCollection=0&layoutCollectionProperty=&layoutCollectionState=0&pagerPage=1

I need to detect layoutCollectionState= and replace any number, here "0", by whatever number I need. I read about String's index and insert methods, but they dont exactly do the job I need them to do.

6
  • only the first number after the "=" sign? Commented Oct 12, 2015 at 20:31
  • any number it might be Commented Oct 12, 2015 at 20:35
  • so if you have layoutCollectionState=2324 you want to replace 2324 by something else correct? Commented Oct 12, 2015 at 20:37
  • exactly what I want @Cyzanfar Commented Oct 12, 2015 at 20:50
  • Then @engineersmnky answer works fine Commented Oct 12, 2015 at 20:54

2 Answers 2

3

URLs are complex and you'll save yourself a lot of work, and potential trouble, by using a library designed for manipulating them instead of trying to roll your own with regular expressions. Fortunately, Ruby comes with a few, among them URI. Using it is easy:

require "uri"

str = "/ei/sort.do?layoutCollection=0&layoutCollectionProperty=&layoutCollectionState=0&pagerPage=1"

# Create a URI object to easily get the query portion of the string
uri = URI(str)

# Decode the query values into a Hash
query = URI.decode_www_form(uri.query).to_h
# Or, if you're using Ruby 2.0 or earlier:
# query = Hash[URI.decode_www_form(uri.query)]

puts query
# => { "layoutCollection" => "0",
#      "layoutCollectionProperty" => "",
#      "layoutCollectionState" => "0",
#      "pagerPage" => "1"
#   }

# Change any values we want to change
query["layoutCollectionState"] = "SOME_OTHER_VALUE"

# Re-encode the query values and assign them back to the URI object
uri.query = URI.encode_www_form(query)

# Turn it back into a string
puts uri.to_s
# => /ei/sort.do?layoutCollection=0&layoutCollectionProperty=&
#    ... layoutCollectionState=SOME_OTHER_VALUE&pagerPage=1

And for what it's worth it needn't be that verbose:

def merge_query_values(url, hsh)
  URI(url).tap do |uri|
    uri.query = URI.encode_www_form(
                  URI.decode_www_form(uri.query).to_h.merge!(hsh) )
  end.to_s
end

str = "/ei/sort.do?layoutCollection=0&layoutCollectionProperty=&layoutCollectionState=0&pagerPage=1"

puts merge_query_values(str, "layoutCollectionState" => "SOME_OTHER_VALUE",
                             "foo" => "BAR")
# => /ei/sort.do?layoutCollection=0&layoutCollectionProperty=&
#    ... layoutCollectionState=SOME_OTHER_VALUE&pagerPage=1&foo=BAR
Sign up to request clarification or add additional context in comments.

5 Comments

This is the most proper way to manipulate a url but definitely will require some additional handling for things like layoutCollectionState not being present or a malformed URI but I would definitely recommend this especially if they needed additional manipulation.
You had a badly formatted trailing code snippet for merge_query_values. I corrected the formatting but you'll need to edit to decide which definition of merge_query_values you want to display, or explain why the second definition is significant.
Oops. Thanks @theTinMan. I meant to delete the second; it was overly clever and didn't work quite right. ;)
"Ruby comes with a few"... well, no. It comes with URI. Addressable::URI is an available gem that is more full-featured.
It also comes with CGI. So that's two. And if you're using Rails you've already got Rack::Utils loaded.
2

The simple way would be to use String#gsub with a regex pattern like so

s = '/ei/sort.do?layoutCollection=0&layoutCollectionProperty=&layoutCollectionState=0&pagerPage=1'
s.gsub(/(?<=layoutCollectionState=)\d+/,'4') 
#=>"/ei/sort.do?layoutCollection=0&layoutCollectionProperty=&layoutCollectionState=4&pagerPage=1"

Here I substituted "0" for "4" (change "4" to whatever you want to use).

This uses a look behind pattern ((?<=layoutCollectionState=)) and then captures the digits that follow this pattern as the item to be replaced. It then replaces this with the second parameter ("4" in this case)

2 Comments

While it's pretty safe changing a numeric value, using sub or gsub with alpha substitution isn't a good idea as it'd be easy to inject invalid characters resulting in an incorrectly encoded URL. That's why we use tools like URI or Addressable::URI, which are aware of the specs.
@theTinMan I am aware of the implications and endorsed Jordans answer. Thank you for your comment but I think you meant that's why we 'have' tools like URI. This solution adequately answers the question and maintains spec when used as directed. The tools used are the choice of the creator not the viewer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.