我目前正在使用前沿的东西编写一个rails应用程序。 Rails3,rSpec2,Ruby 1.9.2和Geokit 1.5.0。当我尝试对具有非ASCII-8Bit特殊字符的地址进行地理编码时,我收到此错误:
不兼容的字符编码: UTF-8和ASCII-8BIT
Trace就像这样:
1) Spot Basic Validations should calculate lat and lng
Failure/Error: spot = Spot.create!({
incompatible character encodings: UTF-8 and ASCII-8BIT
# /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/geokit-1.5.0/lib/geokit/geocoders.rb:435:in `do_geocode'
# /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/geokit-1.5.0/lib/geokit/geocoders.rb:126:in `geocode'
# ./app/models/spot.rb:26:in `geocode_address'
# /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activesupport-3.0.0.rc/lib/active_support/callbacks.rb:409:in `_run_validation_callbacks'
# /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activemodel-3.0.0.rc/lib/active_model/validations/callbacks.rb:53:in `run_validations!'
# /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activemodel-3.0.0.rc/lib/active_model/validations.rb:168:in `valid?'
# /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/validations.rb:55:in `valid?'
# /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/validations.rb:75:in `perform_validations'
# /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/validations.rb:49:in `save!'
# /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/attribute_methods/dirty.rb:30:in `save!'
# /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/transactions.rb:242:in `block in save!'
# /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/transactions.rb:289:in `block in with_transaction_returning_status'
# /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/connection_adapters/abstract/database_statements.rb:139:in `transaction'
# /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/transactions.rb:204:in `transaction'
# /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/transactions.rb:287:in `with_transaction_returning_status'
# /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/transactions.rb:242:in `save!'
# /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/validations.rb:34:in `create!'
# ./spec/models/spot_spec.rb:13:in `block (2 levels) in <top (required)>'
我在所有相关文件(规格,工厂和型号)中都使用了# coding: utf-8
。但是当我使用像“ElsassersStraße27”这样的地址时,我得到了这个错误。
任何提示?我认为Geokit已经与1.9.1兼容,因此与所有这些新的编码事物兼容。
答案 0 :(得分:3)
使用CGI.escape不是一个好主意,因为它会产生意想不到的结果。尝试使用和不使用CGI.escape的“挪威奥斯陆”,你会明白我的意思。
更好的解决方案是在位置使用Iconv:
ic = Iconv.new('US-ASCII//IGNORE', 'UTF-8')
utf8location = ic.iconv(location)
干杯!
编辑:我有Wes Gamble的建议在这里进行编辑,我认为这是相关的:使用//IGNORE
将删除所有非ASCII字符。但是在许多(大多数)情况下,你可能想要翻译某些字符,例如变音符号(例如“苏黎世”将成为“苏黎世”)或者carons(例如“Niš”将成为“Nis”)以便成功地对它们进行地理编码。如果忽略非ASCII字符,则“Zürich”将变为“Zrich”,“Niš”将变为“Ni”,两者都不会成功地进行地理编码。
为此你要使用
ic = Iconv.new('US-ASCII//TRANSLIT', 'UTF-8')
请注意,如果无法完成音译,转换将引发异常,因此请确保您处理。
答案 1 :(得分:1)
CGI.escape似乎比Geokit :: Inflector :: url_escape更准确。
以下是编码“ElsassersStraße27”的结果
>> CGI.escape(address)
=> "Elsassers+Stra%C3%9Fe+27"
虽然
>> Geokit::Inflector::url_escape(address)
=> "Elsassers+Stra%C3e+27"
字母ß应显示为c39F(根据http://www.utf8-chartable.de/unicode-utf8-table.pl)
此外,调试声明正在爆炸(我知道有理由检查是否启用了调试日志记录:)
所以,这是我对GoogleGeocoder3的解决方案,我猜其他人会有类似的问题
module Geokit
module Geocoders
class GoogleGeocoder3 < Geocoder
def self.do_geocode(address, options = {})
bias_str = options[:bias] ? construct_bias_string_from_options(options[:bias]) : ''
address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
#use CGI.escape instead of Geokit::Inflector::url_escape
url ="http://maps.google.com/maps/api/geocode/json?sensor=false&address=#{CGI.escape(address_str)}#{bias_str}"
res = self.call_geocoder_service(url)
return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
json = res.body
# escape results of json
logger.debug "Google geocoding. Address: #{address}. Result: #{CGI.escape(json)}"
return self.json2GeoLoc(json, address)
end
end
end
end
答案 2 :(得分:0)
您使用的是Postgres和pg gem v0.8吗?升级到0.9
答案 3 :(得分:0)
我知道这是一个非常晚的答案,但我已经为Geokit gem编写了一个Google地理编码器来处理所有这些不兼容错误。此Geocoder使用Google的地理编码服务的最新V3 API。优点是现在它不解析XML,而是更快的JSON,与所需的宝石Yajl(ruby的超快速json解析器)配对更快。我的基准测试显示比旧方法快1.5倍。
答案 4 :(得分:-1)
我遇到了同样的问题,我通过添加CGI.escape()解决了这个问题:
geo = Geokit::Geocoders::MultiGeocoder.geocode(CGI.escape(address))