ruby 1.9:UTF-8中无效的字节序列

我在Ruby(1.9)中编写一个爬取器,从大量的随机站点中消耗大量的HTML。
当试图提取链接时,我决定只使用.scan(/href="(.*?)"/i)而不是nokogiri / hpricot(主要加速)。 问题是我现在收到很多“ invalid byte sequence in UTF-8 ”错误。
从我的理解, net/http库没有任何编码特定的选项,进来的东西基本上没有正确标记。
实际使用传入数据的最佳方式是什么? 我尝试使用replace和无效的选项设置.encode ,但目前为止没有成功…

在Ruby 1.9.3中,可以使用String.encode来“忽略”无效的UTF-8序列。 这是一个可以在1.8( iconv )和1.9( String#encode )中工作的片段:

 require 'iconv' unless String.method_defined?(:encode) if String.method_defined?(:encode) file_contents.encode!('UTF-8', 'UTF-8', :invalid => :replace) else ic = Iconv.new('UTF-8', 'UTF-8//IGNORE') file_contents = ic.iconv(file_contents) end 

或者如果你有非常麻烦的input,你可以做一个从UTF-8到UTF-16的双重转换,然后回到UTF-8:

 require 'iconv' unless String.method_defined?(:encode) if String.method_defined?(:encode) file_contents.encode!('UTF-16', 'UTF-8', :invalid => :replace, :replace => '') file_contents.encode!('UTF-8', 'UTF-16') else ic = Iconv.new('UTF-8', 'UTF-8//IGNORE') file_contents = ic.iconv(file_contents) end 

接受的答案或其他答案对我来说都是适合的。 我发现这个post是build议的

 string.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '') 

这为我解决了这个问题。

我目前的解决scheme是运行:

 my_string.unpack("C*").pack("U*") 

这至less会摆脱我这个主要问题的例外

尝试这个:

 def to_utf8(str) str = str.force_encoding('UTF-8') return str if str.valid_encoding? str.encode("UTF-8", 'binary', invalid: :replace, undef: :replace, replace: '') end 

我build议你使用一个HTMLparsing器。 只要find最快的一个。

parsingHTML并不像看起来那么简单。

浏览器在UTF-8 HTML文档中parsing无效的UTF-8序列,只是放置“ ”符号。 因此,一旦HTML中的无效UTF-8序列被parsing,结果文本就是一个有效的string。

即使在属性值内,你也必须解码像放大器这样的HTML实体

下面是一个很好的问题,总结了为什么你不能可靠地使用正则expression式parsingHTML: RegEx匹配除XHTML自包含标签之外的开放标签

我遇到了string,其中有英文,俄文和其他一些字母的混合,这引起了exception。 我只需要俄语和英语,而这个目前适用于我:

 ec1 = Encoding::Converter.new "UTF-8","Windows-1251",:invalid=>:replace,:undef=>:replace,:replace=>"" ec2 = Encoding::Converter.new "Windows-1251","UTF-8",:invalid=>:replace,:undef=>:replace,:replace=>"" t = ec2.convert ec1.convert t 
 attachment = file.read begin # Try it as UTF-8 directly cleaned = attachment.dup.force_encoding('UTF-8') unless cleaned.valid_encoding? # Some of it might be old Windows code page cleaned = attachment.encode( 'UTF-8', 'Windows-1252' ) end attachment = cleaned rescue EncodingError # Force it to UTF-8, throwing out invalid bits attachment = attachment.force_encoding("ISO-8859-1").encode("utf-8", replace: nil) end 

当Nakilon的解决scheme起作用的时候,至less就这个错误而言,在我的情况下,我把这个来自Microsoft Excel的奇怪的f-ed字符转换成CSV,在Ruby中注册为(得到这个)西里尔字母Kruby是粗体K.为了解决这个问题,我使用了“iso-8859-1”即。 CSV.parse(f, :encoding => "iso-8859-1") ,这使我的怪异的西里尔字母K变成了一个更容易pipe理的/\xCA/ ,然后我可以用string.gsub!(/\xCA/, '')

这似乎工作:

 def sanitize_utf8(string) return nil if string.nil? return string if string.valid_encoding? string.chars.select { |c| c.valid_encoding? }.join end 

在使用scan之前,请确保所请求的页面的Content-Type标题是text/html ,因为可以链接到不以UTF-8编码的图像。 如果你拿起一个像<link>元素的href ,页面也可以是非html的。 如何检查这个取决于你正在使用的HTTP库。 然后,确保结果只用ASCII String#ascii_only? ascii String#ascii_only? (不是UTF-8,因为HTML只能使用ascii,否则可以使用实体)。 如果这两个testing都通过,则使用scan是安全的。

如果你不关心数据,你可以做一些事情:

search_params = params[:search].valid_encoding? ? params[:search].gsub(/\W+/, '') : "nothing"

我只用了valid_encoding? 通过它。 我是一个search领域,所以我一遍又一遍地find同样的古怪,所以我用了类似的东西:只是为了让系统不中断。 由于我不会控制用户体验在发送此信息之前进行自动validation(例如自动反馈说“虚拟!”),我可以把它拿出来,剥离出来,并返回空白的结果。