0

我目前正在使用最前沿的东西编写一个 Rails 应用程序。Rails3、rSpec2、Ruby 1.9.2 和 Geokit 1.5.0。当我尝试对具有不在 ASCII-8Bit 中的特殊字符的地址进行地理编码时,我收到此错误:

不兼容的字符编码:UTF-8 和 ASCII-8BIT

跟踪是这样的:

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在所有相关文件(规格、工厂和型号)中都使用过。然而,当我使用像“Elsassers Straße 27”这样的地址时,我得到了这个错误。

有什么提示吗?我认为 Geokit 已经与 1.9.1 兼容,因此也与所有这些新编码的东西兼容。

4

5 回答 5

3

使用 CGI.escape 不是一个好主意,因为它会产生意想不到的结果。尝试使用和不使用 CGI.escape 的“挪威奥斯陆”,你会明白我的意思。

更好的解决方案是在该位置使用 Iconv:

ic = Iconv.new('US-ASCII//IGNORE', 'UTF-8')
utf8location = ic.iconv(location)

干杯!

编辑:我有一个 Wes Gamble 的建议在这里进行编辑,我认为这是相关的:

使用//IGNORE将删除任何非 ASCII 字符。但在许多(大多数)情况下,您可能需要音译某些字符,例如变音符号(例如“Zürich”将变为“Zurich”)或卡隆(例如“Niš”将变为“Nis”),以便成功对其进行地理编码。如果忽略非 ASCII 字符,则“Zürich”将变为“Zrich”,“Niš”将变为“Ni”,两者都不会成功进行地理编码。

为此,您要使用

ic = Iconv.new('US-ASCII//TRANSLIT', 'UTF-8')

请注意,如果无法完成音译,则转换将引发异常,因此请确保处理该异常。

于 2011-07-06T11:46:14.047 回答
1

CGI.escape 似乎比 Geokit::Inflector::url_escape 更准确。

这是编码“Elsassers Straße 27”的结果

>> 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
于 2011-08-31T21:24:30.750 回答
0

我知道这是一个非常晚的答案,但我已经为 Geokit gem 编写了一个谷歌地理编码器来处理所有这些不兼容错误。此地理编码器使用谷歌地理编码服务的最新 V3 API。优点是现在它不解析 XML 而是更快的 JSON,与所需的 gem Yajl(Ruby 的超快速 json 解析器)配对更快。我的基准测试显示比旧方法快 1.5 倍。

https://github.com/rubymaniac/geokit-gem

于 2011-02-09T23:27:24.753 回答
0

你在使用 Postgres 和 pg gem v0.8 吗?升级到 0.9

于 2010-09-25T13:35:59.530 回答
-1

我遇到了同样的问题,我通过像这样添加 CGI.escape() 解决了这个问题:

geo = Geokit::Geocoders::MultiGeocoder.geocode(CGI.escape(address))
于 2011-06-06T09:07:38.613 回答