テキスト解析関数

2007-12-11: これも改良するかな


関数の引数の指定方法は、結局最初に戻ってしまいました。
ただ、指定する値の接頭辞に xpath:// もしくは regexp:// を
付けて、動作を分けるという特殊な感じになりました。


正規表現指定と xpath 指定の設定を分けても良かったのだけれども、
設定項目を増やすのだけは嫌だったので、一緒に。


opt のハッシュキーは、Symbol から String へ変更。

require 'rubygems'
require 'hpricot'

def extract_text(text, opt)
  # argument no check

  prefix_xpath  = %q{^\s*xpath://}
  prefix_regexp = %q{^\s*regexp://}

  case opt['record_fetch']
  when /#{prefix_xpath}(.+)/
    xpath = $1
    doc = Hpricot(text)
    record = doc.search(xpath).collect {|r| r.to_s}
  when /#{prefix_regexp}(.+)/
    regexp = $1
    record = text.scan(/#{regexp}/m)
  else
    return []
  end

  item_xpath = Hash[*opt['field_fetch'].map {|k, v| [k, $1] if v =~ /#{prefix_xpath}(.+)/}.compact.flatten]
  item_regexp = Hash[*opt['field_fetch'].map {|k, v| [k, $1] if v =~ /#{prefix_regexp}(.+)/}.compact.flatten]

  data = []

  record.each {|r|
    item = {}

    if item_regexp.size
      item_regexp.each_pair {|key, val| 
        item[key] = r.match(/#{val}/m).to_a[1]
      }
    end

    if item_xpath.size
      doc = Hpricot(r)

      item_xpath.each {|key, val| 
        elem = doc.at(val)
        if elem.nil?
          item[key] = ''
        else
          item[key] = elem.to_s
        end
      }
    end

    if opt.key?('after_hook')
      eval(opt['after_hook'])
    end

    data << item
  }

  data
end
  • サンプル
    config = YAML.load(<<'EOD')
record_fetch: regexp://<item>.+?</item>
field_fetch:
  name: regexp://<name>(.+?)</name>
  date: regexp://<date>(.+?)</date>
  comment: xpath://comment
  id: regexp://<id>(.+?)</id>
after_hook: |
    item['comment'] = item['comment'].match(/>(.+?)<\//).to_a[1]
EOD

    data = extract_text(@text, config)