Logo

使用 spreadsheet gem 读取 Excel 单元格中内嵌的 hyperlink

avatar hugo 12 Jan 2015

如何使用 spreadsheet gem 读取 Excel 单元格中内嵌的 hyperlink

Task

读取 xls 后缀的 MS Excel 文件中单元格的内容及内嵌其中的 hyperlink。

Solution

require 'spreadsheet'

excel = Spreadsheet.open "/path/to/excel.xls"
sheet = excel.worksheet "sheet_name"

sheet.each do |row|
  if row[0].respong_to?(:href)
    puts "#{row[0]}: #{row[0].href}"
  end
end

(假设第一列的单元格都内嵌了 hyperlink。)

spreadsheet 文档中有写到:

To access the values stored in a Row, treat the Row like an Array.

  row[0]

-> this will return a String, a Float, an Integer, a Formula, a Link or a Date or DateTime object - or nil if the cell is empty.

如果某个单元格内嵌了 hyperlink,row[i] 就会直接返回 Spreadsheet::Link class,然后可以通过 #url#href (url with fragment appended if present) 来获取内嵌的 hyperlink。

=== tl;dr ===

上面是经过简化的内容,只专注标题的意思。下面就啰嗦一下,讲讲整个过程。

Task 本来是要读取一个 xlsx 格式的 Excel,里面是一列几千条的学校名字数据,学校名字内嵌了该校主页的链接,最终目的是读取学校名和主页 hyperlink,存到数据库里以备后用。

一开始是先使用 spreadsheet gem 的,试了一下就发现其不能打开 xlsx 格式的 Excel。将源文件转换成 xls 格式后,能读取数据。然后看了文档很久也没有发现怎么在读取单元格的同时,读取其内嵌的 hyperlink。只是发现有 Spreadsheet::Link 这个类,但是文档里写的却是关于单元格的事例,没有读取的说明。

后来通过使用 pry 来 debug,才发现原来当单元格内嵌了 hyperlink,row[i] 就会返回 Spreadsheet::Link class(通过运行 row[i].class 命令知道的)。虽然调用 row[i].href 能拿到链接了,但是返回值却有乱码(类似 “http://homepage.com/烫烫\u1234\u5678” 的字符串,前面纯 ASCII 字符部分是正确的,只是后面多了一些汉字和 unicode)。

发现读取的值不太对后,就转而尝试 Roo 这个可以直接读取 xlsx 格式的 gem。看了一圈文档并写了一些实验性代码后,没有发现读取单元格内嵌链接的接口。

最终就又切换回使用 spreadsheet 这个 gem,使用 regex 只匹配出 ASCII 字符来去掉乱码。最终进入代码库的 regex:

    /[:\.\/\w\d]+/