测试正则表达式时ruby 1.9字符转换错误

时间:2012-03-10 12:53:42

标签: ruby utf-8 character-encoding nokogiri

我知道那里有很多文档和辩论,但仍然:

这是我对Rails尝试测试来自各个网站的数据的最佳镜头。奇怪的事实是,如果我手动复制粘贴URL的来源一切正常。

我该怎么办?

# encoding: utf-8

require 'rubygems'
require 'iconv'
require 'nokogiri'
require 'open-uri'
require 'uri'

url = 'http://www.website.com/url/test'

sio = open(url)
@cur_encoding = sio.charset
doc = Nokogiri::HTML(sio, nil, @cur_encoding)
txtdoc = doc.to_s

# 1) String manipulation test
p doc.search('h1')[0].text # "Nove36  "
p doc.search('h1')[0].text.strip! # nil <- ERROR


# 2) Regex test
# txtdoc = "test test 44.00 € test test" # <- THIS WORKS
regex = "[0-9.]+ €"


p /#{regex}/i =~ txtdoc # integer expected

我意识到可能我的操作系统Ubuntu加上我的文本编辑器正在对一些破碎的编码进行一些很好的编码转换:那很好,但是如何在我的应用程序运行时解决这个问题呢?

2 个答案:

答案 0 :(得分:3)

  

@cur_encoding = doc.encoding#ISO-8859-15

ISO-8859-15不是引用页面的正确编码;应该是UTF-8。将它标记为UTF-8就好像是8859-15只会使问题复杂化。

此编码来自文档中的错误<meta>标记。浏览器将忽略该标记并使用Content-Type: text/html;charset=utf-8 HTTP响应标头中的重写编码。

然而,Nokogiri似乎无法从open() ed流中读取此标头。虽然我对Ruby一无所知,但在查看源代码时,问题似乎是它使用了来自string-or-IO而不是encoding的属性charset,这似乎是{ {1}}写道。

您可以传递自己的覆盖编码,所以我想尝试:

open-uri

答案 1 :(得分:2)

您遇到的问题是由页面中的非空格字符(Unicode U + 00A0)引起的。

在第一个问题中,字符串:

"Nove36  "

实际上以U + 00A0结尾,String#strip!不认为此字符是要删除的空格:

1.9.3-p125 :001 > s = "Foo \u00a0"
 => "Foo  " 
1.9.3-p125 :002 > s.strip
 => "Foo  "    #unchanged

在你的第二个问题中,价格和欧元符号之间的空间再次是一个非突破空间,因此正则表达式不匹配,因为它正在寻找正常空间:

# s as before
1.9.3-p125 :003 > s =~ /Foo  / #2 spaces, no match
 => nil 
1.9.3-p125 :004 > s =~ /Foo /  #1 space, match
 => 0 
1.9.3-p125 :005 > s =~ /Foo \u00a0/  #space and non breaking space, match
 => 0

当您复制并粘贴源时,浏览器可能会将非中断空格标准化,因此您只能复制普通空格字符,这就是它以这种方式工作的原因。

最简单的解决方法是在开始处理之前对\u00a0进行全局替换:

sio = open(url)
@cur_encoding = sio.charset

txt = sio.read             #read the whole file
txt.gsub! "\u00a0", " "    #global replace

doc = Nokogiri::HTML(txt, nil, @cur_encoding)   #use this new string instead...