2012年1月10日火曜日

Rubyでコーパス言語学(1)

京都大学テキストコーパスをXML形式に変換する

京都大学テキストコーパスは毎日新聞95年度版のデータに構文情報や形態素情報をタグ付けしたものであり、おおよそKNPの出力形式になっている。このコーパスをRubyなどのスクリプトで処理しやすいようにXML形式に変換する。XML形式は、CaboChaのXML形式に似せたものを用いる。

[kc2xml.rb]
# -*- coding: utf-8 -*-

# kc2xml.rb ver 0.20 [2011.8.26]

require 'nokogiri'

module KC2XML

def KC2XML.parse(file)
  xml = Nokogiri::XML::Document.new
  xml.encoding = 'UTF-8'
  xml << doc = xml.create_element('document')
  sen = chu = tag = tok = tokid = nil
  lines = open(file, 'r:eucjp-ms:utf-8'){|f| f.readlines}
  lines.each do |line|
    items = line.split(' ')
    case items[0]
    when '#'
      attr = Hash.new
      items.each do |item|
        k, v = item.split(':')
        attr[k] = v
      end
      sen = xml.create_element('sentence', attr)
      doc << sen
      tokid = 0
    when '*'
      attr = Hash.new
      attr['id'] = items[1]
      attr['link'] = items[2][0 .. -2]
      attr['rel'] = items[2][-1]
      chu = xml.create_element('chunk', attr)
      sen << chu
    when '+'
      attr = Hash.new
      attr['id'] = items[1]
      attr['link'] = items[2][0 .. -2]
      attr['rel'] = items[2][-1]
      tag = xml.create_element('tag', attr)
      tag.add_child items[3] if items[3]
      chu << tag
    when 'EOS'; # nothing to do
    else
      attr = Hash.new
      attr['id'] = tokid
      attr['read'] = items[1]
      attr['base'] = items[2]
      attr['pos'] = items[3 .. 4].delete_if{|s| s == '*'}.join('-')
      attr['ctype'] = items[5]
      attr['cform'] = items[6]
      text = items[0]
      tok = xml.create_element('tok', text, attr)
      (tag or chu) << tok
      tokid += 1
    end
  end
  return doc.to_xml
end

def KC2XML.auto_conv(dir = '.', code = 'eucjp-ms')
  Dir.mkdir('./xml') unless FileTest.directory?('./xml')
  Dir.mkdir("./xml/syn") unless FileTest.directory?("./xml/syn")
  Dir.mkdir("./xml/rel") unless FileTest.directory?("./xml/rel")
  for subdir in ['syn', 'rel']
    files = Dir.glob(File.join(dir, "dat/#{subdir}/*.KNP"))
    files.each do |file|
      STDERR.print file
      des = "./xml/#{subdir}/#{File.basename(file, '.KNP')}.xml"
      STDERR.puts ' -> ' + des
      open(des, 'w', :encoding => code){|f| f.puts parse(file)}
    end
  end
end

end

KC2XML.auto_conv *ARGV[0, 2] if $0 == __FILE__


# 修正履歴
# 2011.08.26 ver 0.20
#  - nokogiriを使って全面的に書き直し
#  - sentenceタグの属性は特に調整していない(今後はnokogiri使うつもりなので)
#  - 全角ダッシュの問題はeucjp-ms使ったら解決した。
# 2010.08.30 ver 0.10
#  - Ruby1.9で動くように全面的に書き直し
# 2008.06.02 ver 0.03
#  - MSXMLでparse Errorしないように調整
#    (sentenceタグの属性をS-ID、KNP、MOD、MEMOに限定)
#  - posが「判定詞-*」とかなってたのを「判定詞」に修正
#  - kconvをiconvに差し替え(全角ダッシュがうまく変換されてなかったので)
# 2008.02.18 ver 0.02 tokの属性がずれていたのを修正
# 2008.02.13 ver 0.01

この程度の変換処理であればnokogiriとか使わない方が多分速いのだが、コード量を少なくするためにnokogiriを使用している。このスクリプトは以下のように使用する。

ruby kc2xml.rb c:¥KyotoCorpus4.0 utf-8

第一引数は京大コーパスが置いてあるフォルダ(C:¥KyotoCorpus4.0など)、第二引数は出力するXMLファイルの文字コードである。kc2xml.rbをあらかじめKyotoCorpus4.0フォルダに置いておけば、第一引数は省略できる(デフォルトはカレントフォルダ)。第二引数を省略した場合は、eucjp-msで出力する。なお、出力するXMLファイルはカレントフォルダ以下にxmlという名前のフォルダを作成し、その中に作成される。

0 件のコメント:

コメントを投稿