如何从字符串中提取包含非英语字符的URL?

时间:2012-01-31 16:04:16

标签: ruby-on-rails ruby string url uri

这是一个简单的脚本,它带有一个带有德国URL的锚标记,并提取URL:

# encoding: utf-8

require 'uri'

url = URI.extract('<a href="http://www.example.com/wp content/uploads/2012/01/München.jpg">München</a>')

puts url

http://www.example.com/wp-content/uploads/2012/01/M

extract方法在ü处停止。如何才能使用非英文字母?我正在使用ruby-1.9.3-p0。

3 个答案:

答案 0 :(得分:12)

Ruby的内置URI对某些内容很有用,但在处理国际字符或IDNA地址时它并不是最佳选择。为此,我建议使用Addressable gem。

这是一些清理过的IRB输出:

require 'addressable/uri'
url = 'http://www.example.com/wp content/uploads/2012/01/München.jpg'
uri = Addressable::URI.parse(url)

这就是Ruby现在所知道的:

#<Addressable::URI:0x102c1ca20
    @uri_string = nil,
    @validation_deferred = false,
    attr_accessor :authority = nil,
    attr_accessor :host = "www.example.com",
    attr_accessor :path = "/wp content/uploads/2012/01/München.jpg",
    attr_accessor :scheme = "http",
    attr_reader :hash = nil,
    attr_reader :normalized_host = nil,
    attr_reader :normalized_path = nil,
    attr_reader :normalized_scheme = nil
>

看着路径,你可以看到它,或者它应该是:

1.9.2-p290 :004 > uri.path            # => "/wp content/uploads/2012/01/München.jpg"
1.9.2-p290 :005 > uri.normalized_path # => "/wp%20content/uploads/2012/01/M%C3%BCnchen.jpg"

考虑到互联网如何转向更复杂的URI和混合的Unicode字符,应该选择Addressable来替换Ruby的URI。

现在,获取字符串也很容易,但取决于您需要查看多少文本。

如果您有完整的HTML文档,最好的办法是使用Nokogiri来解析HTML并从href标记中提取<a>参数。这是单个<a>开始的地方:

require 'nokogiri'
html = '<a href="http://www.example.com/wp content/uploads/2012/01/München.jpg">München</a>'
doc = Nokogiri::HTML::DocumentFragment.parse(html)

doc.at('a')['href'] # => "http://www.example.com/wp content/uploads/2012/01/München.jpg"

使用DocumentFragment进行解析可避免将片段包装在通常的<html><body>标记中。对于您想要使用的完整文档:

doc = Nokogiri::HTML.parse(html)

这是两者之间的区别:

irb(main):006:0> Nokogiri::HTML::DocumentFragment.parse(html).to_html
=> "<a href=\"http://www.example.com/wp%20content/uploads/2012/01/M%C3%BCnchen.jpg\">München</a>"

irb(main):007:0> Nokogiri::HTML.parse(html).to_html
=> "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html><body><a href=\"http://www.example.com/wp%20content/uploads/2012/01/M%C3%BCnchen.jpg\">München</a></body></html>\n"

因此,使用第二个用于完整的HTML文档,对于一个小的部分块,请使用第一个。

要扫描整个文档,提取所有href,请使用:

hrefs = doc.search('a').map{ |a| a['href'] }

如果您的示例中只显示小字符串,则可以考虑使用简单的正则表达式来隔离所需的href

html[/href="([^"]+)"/, 1]
=> "http://www.example.com/wp content/uploads/2012/01/München.jpg"

答案 1 :(得分:4)

您必须首先对网址进行编码:

URI.extract(URI.encode('<a href="http://www.example.com/wp_content/uploads/2012/01/München.jpg">München</a>'))

答案 2 :(得分:0)

URI模块可能仅限于7位ASCII字符。虽然UTF-8是很多东西的假定标准,但这绝不可靠,并且没有办法像完成HTTP交换一样指定URI的编码。

一种解决方案是将非ASCII字符渲染为它们的%等价物。相关的Stack Overflow帖子:Unicode characters in URLs

如果您正在处理已经损坏的数据,您可能需要首先调用URI.encode来识别它,然后再次与之匹配。