TABインデントのテキストファイルをFreeMindのファイルへ変換するRubyスクリプト

http://d.hatena.ne.jp/dogatana/20090131/1233396767 の逆のことをするRubyスクリプトを書いてみました。(あれは空白でインデントするので厳密には逆ではないです。あれもそのうち修正しよう)

1段ずつ木が深くなっていく場合は簡単だったけど、2段以上に対応しようとしてごちゃごちゃしてきた。もっとうまい方法があるはずだと思うのだけれど。

2009-2-8 デバッグ用表示のコメントアウトがあって恥ずかしかったので修正 ^^;

#! ruby -Ks

# text2mm.rb
# http://d.hatena.ne.jp/dogatana/

require 'rexml/document'
require 'iconv'
require 'CGI'

# インデントつきテキストファイルを読み込む
class TextReader
  def initialize(filename)
    @f.close if @f
    begin
      @f = open(filename)
    rescue => e
      puts e
      return nil
    end
  end

  def read
    return nil unless @f
    while s = @f.gets
      if /^(\t*)[^\t]*$/ =~ s
        line = s.strip
        next if line == ""
        level = $1 ? $1.size : 0
        return [level, line, 0]
      end
    end
    return nil  # EOF
  end
end

# 漢字、半角カナを数値表現 &#xxxx; へ変換
def encode_jpnchar(str)
  if str.size == 2
    ustr = Iconv.conv('UTF-16', 'SJIS', str)
    return sprintf("&#x%02x%02x;", ustr[2], ustr[3])
  elsif str.size == 1 && 0xa0 < str[0] && str[0] < 0xe0
    ustr = Iconv.conv('UTF-16', 'SJIS', str)
    return sprintf("&#x%02x%02x;", ustr[2], ustr[3])
  else
    return str
  end
end

def escape(str)
  print "#{str} => " if $DEBUG
  a = CGI.escapeHTML(str).split(//)
  a.each_with_index { |c, i|
    a[i] = encode_jpnchar(c)
  }
  return a.join
end

# xmlツリーの作成
def make_tree(txt, root, a, nest = 0)
  if a[2] > 0 
    leaf = root.add_element("node", { "TEXT" => " "})
    a[2] -= 1
    a = make_tree(txt, leaf, a)
    if a && a[2] < 0
      a[2] += 1
      return a
    end
  end
  while a
    leaf = root.add_element("node", { "TEXT" => escape(a[1])})
    unless new_a = txt.read
      return nil
    end
    if new_a[0] == a[0]
      a = new_a
    elsif new_a[0] > a[0]
      new_a[2] = new_a[0] - a[0] - 1
      a = make_tree(txt, leaf, new_a)
      if a && a[2] < 0
        a[2] += 1
        return a
      end
    else
      new_a[2] = new_a[0] - a[0] + 1
      return new_a
    end
  end
  return nil
end



# ==== main

if ARGV.size != 1
  puts "usage: text2mm textfile"
  exit
end

txt = TextReader.new(ARGV[0])
unless txt && a = txt.read
  exit
end

printf("[%d] '%s'\n", a[0], a[1]) if $debug

doc = REXML::Document.new
map = doc.add_element("map", { "version" => "0.8" })
REXML::Comment.new('this is generated by text2mm by dogatana@gmail.com', map)

root = map.add_element("node", { "TEXT" => "#{escape(File.basename(ARGV[0], '.*'))}"})

a[0] = 0 # いきなりインデントされている場合
make_tree(txt, root, a)

doc.write(STDOUT, 2)