【问题标题】:Geokit Gem 1.5 and Ruby 1.9.2 => "incompatible character encodings: UTF-8 and ASCII-8BIT"Geokit Gem 1.5 和 Ruby 1.9.2 => “不兼容的字符编码:UTF-8 和 ASCII-8BIT”
【发布时间】:2010-08-16 12:58:03
【问题描述】:

我目前正在使用最前沿的东西编写一个 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。然而,当我使用像“Elsassers Straße 27”这样的地址时,我得到了这个错误。

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

【问题讨论】:

  • 记录器存在问题,据我所知,是哪个产生了编码错误。但是,Geokit 仍然不能正确处理某些输入。对我来说,这是对日语输入的吐槽。我正在尝试制作补丁。
  • 我在我制作的 GeoKit gem 的一个分支中添加了一个测试,它适用于日本地址。但是,当我在 Ruby 1.9.2 上的 Rails 3 应用程序中使用该分叉 gem 时,我仍然收到编码错误。

标签: ruby-on-rails-3 ruby-1.9 geokit rspec2


【解决方案1】:

使用 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')

请注意,如果无法完成音译,转换将引发异常,因此请务必处理好。

【讨论】:

    【解决方案2】:

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

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

    &gt;&gt; CGI.escape(address)

    =&gt; "Elsassers+Stra%C3%9Fe+27"

    虽然

    &gt;&gt; Geokit::Inflector::url_escape(address)

    =&gt; "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
    

    【讨论】:

    【解决方案3】:

    您使用的是 Postgres 和 pg gem v0.8 吗?升级到 0.9

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

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

        geo = Geokit::Geocoders::MultiGeocoder.geocode(CGI.escape(address))
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-07-14
          • 2011-03-14
          • 2014-12-11
          • 2017-02-24
          • 1970-01-01
          • 2011-10-17
          • 1970-01-01
          • 2012-07-12
          相关资源
          最近更新 更多