Basically url escapes a string except uses '+' instead of '%20' for spaces.
CGI::escape does just that:
irb(main):003:0> require 'cgi'
=> true
irb(main):004:0> CGI::escape("foo and/or bar")
=> "foo+and%2For+bar"
Related
It seems to be pretty easy to create nested OpenStruct objects using JSON.parse:
JSON.parse( '{"a":{"b":0}}', object_class:OpenStruct )
#<OpenStruct a=#<OpenStruct b=0>>
Is there a simpler method of converting it back to json, without creating a recursive function (as demonstrated here: Deep Convert OpenStruct to JSON)?
Calling OpenStruct#to_json on your struct should do it:
[2] pry(main)> JSON.parse('{"a":{"b":0}}', object_class:OpenStruct).to_json
=> "{\"a\":{\"b\":0}}"
And from plain irb OpenStruct#to_json does not work:
irb(main):003:0> require 'ostruct'
=> true
irb(main):004:0> require 'json'
=> true
irb(main):005:0> JSON.parse('{"a":{"b":0}}', object_class:OpenStruct).to_json
=> "\"#<OpenStruct a=#<OpenStruct b=0>>\""
ruby 2.5.3, rails 4.2.11.1
Context
I have Rails (4.0.1 + Ruby 2.0.0) connected to a PostgreSQL database filled with strings like "€ 289,95". The values have been scraped from a website using Nokogiri. I want to convert the strings to floating points.
What I've tried
Rails console:
listing = Listing.find(1)
=> #<Listing id: 1, title: #, subtitle: #, name: #, price: "€ 289,95", url: #, created_at: #, updated_at: #>
listing_price = listing.price
=> "€ 289,95"
listing_price_1 = listing_price.gsub(/,/, ".")
=> "€ 289.95"
listing_price_2 = listing_price_1.gsub(/€\s/, "")
=> "€ 289.95"
listing_price_3 = listing_price_2.to_f
=> 0.0
Problem
The code works in irb but doesn't work in the rails console.
What I want to know
How to convert a string "€ 289,95" to a float "289.95" in Rails?
The step where your technique is failing is when trying to strip away € and the space from € 289.95 with the regexp /€\s/, but this is not matching, leaving the string unchanged.
The space character in € 289,95 is probably a non-breaking space (U+00A0) rather than a “normal” space, and would be used in the web page so that the € and the value are not separated.
In Ruby the non-breaking space is not matched by \s in a regexp, so your call to gsub doesn’t replace anything:
2.0.0p353 :001 > s = "€\u00a0289.95"
=> "€ 289.95"
2.0.0p353 :002 > s.gsub(/€\s/, "")
=> "€ 289.95"
Non-breaking space is matched by the POSIX bracket expression [[:space:]], or by the character property \{Blank}:
2.0.0p353 :003 > s.gsub /€[[:space:]]/, ""
=> "289.95"
2.0.0p353 :004 > s.gsub /€\p{Blank}/, ""
=> "289.95"
So if you wanted a more specific regexp than in the other answer you could use one of these.
"€ 289,95".sub(/\A\D+/, "").sub(",", ".").to_f
# => 289.95
listing.price.delete('€ ') # => "289,95"
listing.price.delete('€ ').tr(',', '.') # => "289.95"
listing.price.delete('€ ').tr(',', '.').to_f # => 289.95
String's 'delete' method is good for removing all occurrences of the target strings.
and 'tr' method takes a string of characters to search for, and a string of characters used to replace them.
Better probably than the accepted answer is:
"€ 289,95"[/[\d,.]+/].tr ',', '.'
I have a string like
"car\"
which I will be storing in postgres db. I want to remove the backslash from the string before saving. Is there a way I can do that in ruby or in postgres? When I try to remove it in ruby, it considers the quote after the backslash as an escape character.
See following code:
1.9.3p125 :022 > s = "cat\\"
=> "cat\\"
1.9.3p125 :023 > puts s
cat\
=> nil
1.9.3p125 :024 > s.chomp("\\")
=> "cat"
1.9.3p125 :025 >
People don't do this much, but Ruby's String class supports:
irb(main):002:0> str = 'car\\'
=> "car\\"
irb(main):003:0> str[/\\$/] = ''
=> ""
irb(main):004:0> str
=> "car"
It's a conditional search for a trailing '\', and replacement with an empty string.
To remove a trailing backslash:
"car\\".gsub!(/\\$/, "")
Note that the backslash has to be escaped itself with a backslash.
puts '"car\"'.gsub(/\\(")?$/, '\1')
that will do it,
but, is the trailing slash always at the en followed by a quote?
See what says the
str.dump
operation, and then try to operate on that.
Not sure why I'm getting the following error when the URI works just fine in the browser:
http://oracleofbacon.org/cgi-bin/xml?a=Kevin Bacon&b=Tom Cruise&u=1&p=google-apps
This is my code:
def kb(to)
uri = "http://oracleofbacon.org/cgi-bin/xml?a=Kevin Bacon&b=#{to.strip}&u=1&p=google-apps"
doc = Nokogiri::XML(open(uri)) # throws error on this line
return parse(doc)
end
I get the following error:
in `split': bad URI(is not URI?): http://oracleofbacon.org/cgi-bin/xml?a=Kevin Bacon&b=Tom Cruise&u=1&p=google-apps (URI::InvalidURIError)`
I execute the method in the following way:
kb("Tom Cruise")
It's because a browser is pathologically friendly, like a puppy, and will go to great lengths to render a page or resolve a URL. An application won't do that because you have to tell it how to be friendly.
Your URL is not valid because it has embedded spaces. Replace the spaces with %20:
irb -f
irb(main):001:0> require 'open-uri'
=> true
irb(main):002:0> open('http://oracleofbacon.org/cgi-bin/xml?a=Kevin%20Bacon&b=Tom%20Cruise&u=1&p=google-apps').read
=> "<?xml version=\"1.0\" standalone=\"no\"?>\n<link><actor>Tom Cruise</actor><movie>A Few Good Men (1992)</movie><actor>Kevin Bacon</actor></link>"
Escaping the characters needing to be escaped is easy:
irb -f
irb(main):001:0> require 'uri'
=> true
irb(main):002:0> URI.escape('http://oracleofbacon.org/cgi-bin/xml?a=Kevin Bacon&b=Tom Cruise&u=1&p=google-apps')
=> "http://oracleofbacon.org/cgi-bin/xml?a=Kevin%20Bacon&b=Tom%20Cruise&u=1&p=google-apps"
Suppose I only want user to type in url starts with http://www.google.com
What is the regular expression for this?
Thanks!
Just get the substring from 0 to the length of http://www.google.com and you're done.
Rather than use a regex, you might want to consider using the URI library that comes with Ruby. It's made to take apart and build URLs, is well tested, and less error-prone than trying to reinvent the same functionality.
require 'uri'
url = URI.parse('http://www.google.com/path/to/page.html?a=1&b=2')
url.scheme # => "http"
url.host # => "www.google.com"
url.path # => "/path/to/page.html"
url.query # => "a=1&b=2"
If that's not good enough, the Addressable::URI gem is even more capable.
Try this:
/\Ahttp:\/\/www\.google\.com(.*)?\Z/
ruby-1.9.2-p0 > "http://www.google.com" =~ /\Ahttp:\/\/www\.google\.com(.*)?\Z/
=> 0
ruby-1.9.2-p0 > "http://www.google.com/foobar" =~ /\Ahttp:\/\/www\.google\.com(.*)?\Z/
=> 0
ruby-1.9.2-p0 > $1
=> "/foobar"
Rails has a convenient start_with? method for this. If it's just a static string, no regular expression is needed.
url.start_with?("http://www.google.com")