Geokit Gem 1.5 和 Ruby 1.9.2 => “不兼容的字符编码:UTF-8 和 ASCII-8BIT”

发布于 2024-09-14 20:45:48 字数 2866 浏览 3 评论 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 兼容,因此与所有这些新的编码事物兼容。

I am currently writing a rails app using bleeding edge stuff. Rails3, rSpec2, Ruby 1.9.2 and Geokit 1.5.0. When i try to geocode addresses that have special characters that are not in ASCII-8Bit i get this error:

incompatible character encodings:
UTF-8 and ASCII-8BIT

The Trace is like this:

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

I used # coding: utf-8 in all of my related files (specs, factories and model). Yet i get this error when i use an address like "Elsassers Straße 27".

Any hints? I thought Geokit was already compatible with 1.9.1 and therefore with all this new encoding thing.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

梦晓ヶ微光ヅ倾城 2024-09-21 20:45:49

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

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

I know it a very very late answer, but I have written a Google geocoder for the Geokit gem that handles all of this Incompatibility errors. This Geocoder uses the newest V3 API of Google's geocoding service. The advantage is that now it does not parse XML but rather JSON which is faster, paired with the required gem Yajl (a super fast json parser for ruby) is way faster. My benchmarks show about 1.5x times faster than the old way.

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

半暖夏伤 2024-09-21 20:45:49

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

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

I had the same problem and I solved this by adding CGI.escape() like this:

geo = Geokit::Geocoders::MultiGeocoder.geocode(CGI.escape(address))
人生戏 2024-09-21 20:45:48

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

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

Using CGI.escape is not a good idea, as it gives unexpected results. Try "Oslo, Norway" with and without CGI.escape, you'll see what I mean.

A better solution is to use Iconv on the location:

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

Cheers!

EDIT: I had a suggestion by Wes Gamble for a edit here, which I think is relevant:

Using //IGNORE will remove any non-ASCII characters. But in many (most) cases, you may want to transliterate certain characters such as umlauts (e.g. "Zürich" will become "Zurich") or carons (e.g "Niš" will become "Nis") in order to successfully geocode them. If you ignore non-ASCII characters, then "Zürich" will become "Zrich" and "Niš" will become "Ni", neither of which will successfully geocode.

For this you want to use

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

Note that the conversion will throw an exception if the transliteration cannot be completed so make sure you handle that.

给妤﹃绝世温柔 2024-09-21 20:45:48

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

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

>> CGI.escape(地址)

=> “Elsassers+Stra%C3%9Fe+27”

>> Geokit::Inflector::url_escape(地址)

=> "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

CGI.escape seems to be more accurate than Geokit::Inflector::url_escape.

Here are the results of encoding "Elsassers Straße 27"

>> CGI.escape(address)

=> "Elsassers+Stra%C3%9Fe+27"

While

>> Geokit::Inflector::url_escape(address)

=> "Elsassers+Stra%C3e+27"

The letter ß should show as c39F (as per http://www.utf8-chartable.de/unicode-utf8-table.pl)

In addition, debug statement was blowing up (I knew there was a reason to check if debug logging is enabled :)

So, here is my solution for GoogleGeocoder3, I guess others will have a similar problem

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
晨曦慕雪 2024-09-21 20:45:48

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

Are you using Postgres and pg gem v0.8? Upgrade to 0.9

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文