UndefinedConversionError尝试从电子邮件正文中解析阿拉伯语

时间:2012-11-02 21:57:45

标签: ruby mongodb encoding utf-8 gmail

使用mail获取ruby我收到此消息:

mail.rb:22:in `encode': "\xC7" from ASCII-8BIT to UTF-8 (Encoding::UndefinedConversionError)
    from mail.rb:22:in `<main>'

如果我删除编码,我会收到一条消息ruby

/var/lib/gems/1.9.1/gems/bson-1.7.0/lib/bson/bson_ruby.rb:63:in `rescue in to_utf8_binary': String not valid utf-8: "<div dir=\"ltr\"><div class=\"gmail_quote\">l<br><br><br><div dir=\"ltr\"><div class=\"gmail_quote\"><br><br><br><div dir=\"ltr\"><div class=\"gmail_quote\"><br><br><br><div dir=\"ltr\"><div dir=\"rtl\">\xC7\xE1\xE4\xD5 \xC8\xC7\xE1\xE1\xDB\xC9 \xC7\xE1\xDA\xD1\xC8\xED\xC9</div></div>\r\n</div><br></div>\r\n</div><br></div>\r\n</div><br></div>" (BSON::InvalidStringEncoding)

这是我的代码:

require 'mail'
require 'mongo'

connection = Mongo::Connection.new
db = connection.db("DB")
db = Mongo::Connection.new.db("DB")
newsCollection = db["news"]

Mail.defaults do
  retriever_method :pop3, :address    => "pop.gmail.com",
                          :port       => 995,
                          :user_name  => 'my_username',
                          :password   => '*****',
                          :enable_ssl => true
end
emails = Mail.last
#Checks if email is multipart and decods accordingly. Put to extract UTF8 from body
plain_part = emails.multipart? ? (emails.text_part ? emails.text_part.body.decoded : nil) : emails.body.decoded

html_part = emails.html_part ? emails.html_part.body.decoded : nil

mongoMessage = {"date" => emails.date.to_s , "subject" => emails.subject , "body" => plain_part.encode('UTF-8') }
msgID = newsCollection.insert(mongoMessage) #add the document to the database and returns it's ID
puts msgID

对于英语和希伯来语,它运作得很好,但似乎gmail正在发送不同编码的阿拉伯语。用UTF-8替换ASCII-8BIT会产生类似的错误。

使用plain_part用于普通电子邮件时,我得到相同的结果。我正在处理来自某个特定来源的电子邮件,因此我可以放心地将html_part放入,但不会导致错误。 使它更加奇怪阿拉伯语中的主题完美呈现。 我应该使用什么编码?

2 个答案:

答案 0 :(得分:2)

如果你使用没有选项的encode,如果你的字符串假装是一个编码但包含来自另一个编码的字符,则会引发此错误。

以这种方式尝试:

plain_part.encode('UTF-8', {:invalid => :replace, :undef => :replace, :replace => '?'})

这将使用“?”(more info)替换给定编码的无效和未定义字符。如果这不足以满足您的需求,您需要找到一种方法来检查您的plain_part字符串是否有效。 例如,您可以使用valid_encoding?more info)。

我最近遇到了类似的问题,我无法确定它的编码是什么,所以我写了这个(可能有点谦虚)的方法。可以帮助您找到解决问题的方法。

def self.encode!(str)
  return nil if str.nil?

  known_encodings = %w(
    UTF-8
    ISO-8859-1
  )

  begin
    str.encode(Encoding.find('UTF-8'))
  rescue Encoding::UndefinedConversionError
    fixed_str = ""
    known_encodings.each do |encoding|
      fixed_str = str
      if fixed_str.force_encoding(encoding).valid_encoding?
        return fixed_str.encode(Encoding.find('UTF-8'))
      end
    end
    return str.encode(Encoding.find('UTF-8'), {:invalid => :replace, :undef => :replace, :replace => '?'})
  end
end

答案 1 :(得分:0)

我找到了一个解决方法。

由于只有特定的电子邮件才会发送到此帐户才能在此应用程序上使用,因此我可以完全控制格式化。由于某种原因,邮件解码text/plain附件完美

这样:

emails.attachments.each do | attachment |
  if (attachment.content_type.start_with?('text/plain'))
    # extracting txt file
    begin
body = attachment.body.decoded
    rescue Exception => e
      puts "Unable to save data for #{filename} because #{e.message}"
    end
  end
end
mongoMessage = {"date" => emails.date.to_s , "subject" => emails.subject , "body" => body }
相关问题