- u = get_char_attribute(a)
- return u if u != nil
- }
- return nil
- end
-
- #----------------------------------------------------------------------CCS関係
- def to_utf8() Uconv.u4tou8(Character.u4itou4(ucs())) end #UTF8文字列を返す
- #alias to_s to_utf8
- alias to_s mcs_utf8
- def map_utf8()
- u = ucs()
- if u.nil? || 0xffff < u
- return to_er()
- else
- return to_utf8()
- end
- end
- alias map_ucs map_utf8
- def map_ucs_er()
- u = ucs()
- if u.nil? || 0xffff < u
- return to_er()
- else
- return Character.get(u).to_er()
- end
- end
- def to_euc()
- u = ucs()
- return "" if u.nil? || 0xffff < u
- Uconv.u16toeuc(Uconv.u4tou16(Character.u4itou4(ucs())))
- end
- def map_euc()
- e = to_euc()
- return e if e != ""
- return to_er()
- end
- def to_sjis()
- u = ucs()
- return "" if u.nil? || 0xffff < u
- Uconv.u16tosjis(Uconv.u4tou16(Character.u4itou4(ucs())))
- end
- def map_sjis()
- e = to_sjis()
- return e if e != ""
- return to_er()
- end
-
- #----------------------------------------------------------------------
- def to_er(codesys=nil) #実体参照を返す、希望するcodesysが引数(未実装)
- return "" if @char_id == nil
- return sprintf("&#x%04x;", @char_id) if @char_id <= 0xffff
- return sprintf("&#x%05x;", @char_id) if @char_id <= 0xfffff
- EntityReference.each_codesys {|codesys, er_prefix, keta, numtype|
- code = self[codesys]
- next if code == nil
- return sprintf("&#{er_prefix}%0#{keta}#{numtype};", code)
- }
- return sprintf("&MCS-%08X;", @char_id) #本当はこれは無しにしたい
- end
- def to_er_list()
- ar = []
- EntityReference.each_codesys {|codesys, er_prefix, keta, numtype|
- er = to_er(codesys)
- ar << er if er != nil
- }
- ar
- end
-
- def inspect_x()
- return "<>" if @char_id == nil
- ar = [to_utf8(), to_er().sub(/^&/,'').chop]
- "<"+ar.join(',')+">"
- end
- alias inspect inspect_x
- def inspect_all_codesys() #未完成
- #to_erを全てのcodesysにおいて実行する。その結果をコンパクトにまとめる
- end
- def inspect_all()
- ar = [inspect.chop]
- alist.to_a.sort.each {|a, v| ar << "#{a}:#{v}" }
- return ar.join(',')+">"
- end
- def get_attributes()
- str = ""
- alist.to_a.sort.each {|a, v|
- str += "#{a}: #{v}\n"
- }
- str
- end
-
- def inspect_ids(hex_flag=false)
- ids = decompose
- ar = []
- ar << (hex_flag ? "x"+mcs_hex : to_utf8)
- if to_s != ids #idsが部品そのものだったら部品追加はしない
- ids.each_char {|ch|
- char = ch.char
- next if char.is_ids?
- if hex_flag then
- ar << "x"+char.mcs_hex
- else
- u = char.to_utf8
- if u != ""
- ar << u
- else
- ar << char.to_er
- end
- end
- }
- end
- return "("+ar.join("\t")+")"
- end
-
- #----------------------------------------------------------------------IDS関係
- def decompose
- k = self.to_s
-# idss = self['ids']
-# return idss if idss
-# return k if self.is_basic_kanji? #基本漢字はstop kanjiとするぞと。
- return self['ids-represent'] if self['ids-represent'] #ids_representを持っている場合はその値とする。
- return self['ids-element'] if self['ids-element'] #ids_elementを持っている場合はその値とする。
-
- idss = self['ids-meaning']
- return idss if idss != nil && 0 < idss.length && k != idss
- idss = self['ids-aggregated']
- return idss if idss != nil && 0 < idss.length && k != idss
- idss = self['ids']
- return idss if idss != nil && 0 < idss.length && k != idss
- return k
-# return k if idss.nil? || idss.length == 0 || k == idss
-# if idss.char_length == 2
-# p ['What???', k, idss, k.inspect_all]
-# #return idssx[1] #二個目だけ返すとか?
-# return k #IDSに展開する方法が無いと。
-# end
-# return k if k == idss
-# if idss.include?(k) #<C5-4C4D><C6-4A37>この二文字のBUG対策
-# #return idss.sub(k, '')
-# return k #IDSに展開する方法が無いと。
-# end
-# return idss
- end
- def decompose_all
- pde = ""
- de = self.decompose #出発点
- level = 0
- while true
- pde = de
- de = pde.decompose #もう一度分解をしてみる。
- break if pde == de #ループを抜けだす
- exit if 10 < level #p ['too many recursive', self]
- level += 1
- end
- return de
- end
- def decompose_all_nu(level=nil)
- level = 0 if level.nil?
- if 10 < level
- p ['too many recursive', self]
- exit
- end
- de = self.decompose
- return de.decompose_all(level+1) if de != self #なにか変化があったから再帰
- return de #もうこれ以上変化は無さそうだぞと。
- end
- def is_ids?() 0x2ff0 <= @char_id && @char_id <= 0x2fff end
- def ids_operator_argc()
- return 0 unless is_ids?
- return 3 if @char_id == 0x2ff2 || @char_id == 0x2ff3
- return 2
- end
- end
-
- class DBS #======================================================================複数のDBを集めたclass、未完成
- end
-
- class ADB < BDB::Hash #======================================================================一つのDB
- def initialize(*args)
- super
- @modified = false
- at_exit {
- if @modified
- self.close #これがないと、うまくデータベースがセーブされないのです。
- end
- }
- end
- def self.open_create(filename)
- ADB.open(filename, nil, BDB::CREATE | BDB::EXCL) #上書きはしない
- end
- def mykey(key)
- if key.is_a?(String)
- if key.char_length == 1
- return '?'+key #Stringだったら引く前に?を足す
- end
- end
- #key = key.to_s if key.is_a?(Numeric) #NumberだったらStringにする。
- #ここで && key ! =~ /^\?/ をいれると、?自身を検索できなくなってしまう。
- return key
- end
- def myvalue(v)
- return v if v == nil
- return v.to_i if v =~ /^\d+$/ #数字だったらここで変換しておく
- return v.sub(/^\?/, '') if v =~ /^\?/ #冒頭の?は取り除く
- return $1 if v =~ /^"(.+)"$/ #最初と最後に"がついていたら、取り除く
- #p ['get', v, t, key, db]
- #return parse_sexp(v) if v =~ /^\(.+\)$/ #最初と最後が()の時は、S式にparseする
- return v #それ以外って何?
- end
- def myget(key) #keyキーを引いて返す
- key = mykey(key)
- v = get(key) #存在しなかったらnilを返すことになる
- return myvalue(v)
- end
- def myput(key, v) #keyにvをいれる
- key = mykey(key)
- put(key, v) #putする
- @modified = true
- end
- end
-
- class DB #======================================================= データベース群のabstract class
- def self.unix_to_win(unix) #Windowsファイル名制限のため、変換する
- win = unix.gsub(/</, '(')
- win.gsub!(/>/, ')')
- win.gsub!(/\*/, '+')
- win.gsub!(/\?/, '!')
- return win
- end
- def self.win_to_unix(win)
- unix = win.gsub(%r|\)|, '>')
- unix.gsub!(%r|\(|, '<')
- unix.gsub!(%r|!|, '?')
- unix.gsub!(%r|\+|, '*')
- return unix
- end
- def get_filename(t)
- return @pre + DB.unix_to_win(t) + @post if windows?
- return @pre + t + @post
- end
- def get_dirname(t) File.dirname(get_filename(t)) end
- def open_dbs()
- @dbs = Hash.new
- keys = find_keys()
- keys.each {|key| open_db(key) }
- end
- def find_keys()
- files = []
- Dir.glob(@glob){|f|
- next if ! File.file?(f)
- next if f =~ /.txt$/
- files << f
- }
- keys = []
- files.each {|f|
- t = DB.win_to_unix(f)
- t.sub!(%r|^#{@pre}|, '')
- t.sub!(%r|#{@post}$|, '') if @post != ""
- keys << t
- }
- return keys
- end
- def close_db(t)
- db = get(t)
- return nil if db.nil?
- db.close
- @dbs.delete(t)
- end
- def open_db(t)
- return nil if get(t) #すでにopenしていたら再openはしない。
- begin
- bdb = ADB.open(get_filename(t), nil, 0)
- @dbs[t] = bdb if bdb != nil
- rescue
- p ["open error", get_filename(t)]; return nil
- end
- return true
- end
- def make_db(t, h=nil) #tという名前でhという中身のデータベースを作る
- return nil if get(t) #すでにある場合はreturn
- Dir.mkdir(get_dirname(t)) unless FileTest.exist?(get_dirname(t))
- db = nil
- begin
- db = ADB.open_create(get_filename(t)) #上書きはしない
- if h != nil
- h.each {|k, v|
- k = '?'+k if k.is_a?(String)
- db[k] = v
- }
- end
- db.close
- rescue
- p ["make error", get_filename(t)]; return nil
- end
- return true
- end
- def make_db_no_question_mark(t, h=nil) #tという名前でhという中身のデータベースを作る
- return nil if get(t) #すでにある場合はreturn
- Dir.mkdir(get_dirname(t)) unless FileTest.exist?(get_dirname(t))
- db = nil
- begin
- db = ADB.open_create(get_filename(t)) #上書きはしない
- if h != nil
- h.each {|k, v|
-# k = '?'+k if k.is_a?(String)
- db[k] = v
- }
- end
- db.close
- rescue
- p ["make error", get_filename(t)]; return nil
- end
- return true
- end
- def remove_db(t) #tという名前のデータベースを消去する
- db = get(t)
- if db
- db.close
- @dbs.delete(t)
- end
- begin
- File.unlink(get_filename(t)) if FileTest.file?(get_filename(t))
- rescue
- p ["unlink error", get_filename(t)]; return nil
- end
- dn = get_dirname(t)
- Dir.rmdir(dn) if FileTest.directory?(dn) && Dir.entries(dn).length <= 2 #空directoryだったら消す
- return true
- end
- def to_num(s)
- return s.to_i if s =~ /^\d+$/
- return s
- end
- def dump_db(t)
- db = get(t)
- return nil unless db
- file = get_filename(t)
- open("#{file}.txt", "w"){|out|
-# out.binmode.sync = true
- ar = db.to_a
- ar.map! {|k, v| [to_num(k), to_num(v)] }
- ar.sort.each {|k, v|
- out.printf("%s\t%s\n", k, v)
- }
- }
- return true
- end
- def each_db() @dbs.to_a.sort.each {|t, db| yield(t, db) } end
- def dump_all() each_db {|t, db| dump_db(t) } end
- def close_all() each_db {|t, db| db.close } end
- def keys() @dbs.keys end
- def each(t)
- return unless block_given?
- db = @dbs[t]
- return nil unless db
- db.each {|k, v|
- k = to_num(k)
- v = to_num(v)
- k.sub!(/^\?/, '') if k =~ /^\?/ #冒頭の?は取り除く
- vv = get(t, k) #p ['each', t, k, v, vv]
- yield(k, vv)
- }
- end
- def each_sort(t)
- return unless block_given?
- db = @dbs[t]
- return nil unless db
- ar = db.to_a
- ar.map! {|k, v| [to_num(k), to_num(v)] }
- ar.sort.each {|k, v|
- k.sub!(/^\?/, '') if k =~ /^\?/ #冒頭の?は取り除く
- vv = get(t, k) #p ['each', t, k, v, vv]
- yield(k, vv)
- }
- end
- #----------------------------------------------------------------------
- def get(t, key=nil) #tというデータベースのkeyキーを引いて返す
- db = @dbs[t]
- return db if key.nil?
- return nil unless db
- return db.myget(key)
- end
- def put(t, key, v) #tというデータベースのkeyにvをいれる
- db = @dbs[t]
- if db == nil
- db = make_db(t)
- db = open_db(t)
- db = @dbs[t]
- end
- db.myput(key, v) #putする
- end
- end
-
- class CharDB < DB #------------------------------------ MCS-UTF8をキーとした属性へのデータベース
- include Singleton
- def initialize()
- super
- @glob, @pre, @post = "#{DB_DIR}/system-char-id/*", "#{DB_DIR}/system-char-id/", ""
- open_dbs()
- end
- def get_all(u8) #全データベースのu8キーを引いてHashにまとめて返す
- atrs = Hash.new
- @dbs.each {|t, db|
- v = get(t, u8)
- atrs[t] = v if v != nil
- }
- return atrs
- end
- end
-
- class CodesysDB < DB #----------------------------------------------------------------------
- include Singleton
- def initialize()
- super
- @glob, @pre, @post = "#{DB_DIR}/*/system-char-id", "#{DB_DIR}/", "/system-char-id"
- open_dbs()
- end
- #def keys() @dbs.keys.sort end #どんなCodesysの情報を持っているかの一覧
- def keys() @dbs.keys end #どんなCodesysの情報を持っているかの一覧
- def get_codesys(t)
- db = get(t)
- return nil unless db
- return Codesys.new(t)
- end
- end
-
- class Codesys < DB #======================================================================
- def initialize(name)
-# super
- @name = name
- @dbs = CodesysDB.instance
- end
- def keys() #どんなコードポイントの情報を持っているかの一覧
- ks = @dbs.get(@name).keys
- if @name =~ /jisx0208/ #特別処理
- n = @dbs.get('=jis-x0208').keys
- # p ['keys', @name, ks, n]
- ks += n
- end
- ks.map! {|k| to_num(k) }
- ks
- end
- def get(key)
- v = @dbs.get(@name, key)
- return v if v
- if @name =~ /jisx0208/ #jisx0208が含まれている場合だけ特別処理する
- return @dbs.get('=jis-x0208', key)
- end
- return nil
- end
- def each()
- return unless block_given?
- db = @dbs.get(@name)
- return nil unless db
- db.each {|k, v|
- k = to_num(k)
- v = to_num(v)
- k.sub!(/^\?/, '') if k =~ /^\?/ #冒頭の?は取り除く
- vv = @dbs.get(@name, k) #p ['each', t, k, v, vv]
- yield(k, vv)
- }
- end
- def each_sort()
- return unless block_given?
- db = @dbs.get(@name)
- return nil unless db
- ar = db.to_a
- ar.map! {|k, v| [to_num(k), to_num(v)] }
- ar.sort.each {|k, v|
- k.sub!(/^\?/, '') if k =~ /^\?/ #冒頭の?は取り除く
- vv = @dbs.get(@name, k) #p ['each', t, k, v, vv]
- yield(k, vv)
- }
- end
- end
-
- class IDS_TEXT_DB < DB #======================================================================
- include Singleton
- if CHISE.windows?()
- IDS_DB_DIR = 'd:/work/chise/ids/' #この後にIDS-JIS-X0208-1990.txtという感じに続く
- else
- IDS_DB_DIR = '/home/eto/work/chise/ids/' #この後にIDS-JIS-X0208-1990.txtという感じに続く
- end
- IDS_LIST = "
-IDS-UCS-Basic.txt
-#IDS-UCS-Compat-Supplement.txt
-#IDS-UCS-Compat.txt
-IDS-UCS-Ext-A.txt
-IDS-UCS-Ext-B-1.txt
-IDS-UCS-Ext-B-2.txt
-IDS-UCS-Ext-B-3.txt
-IDS-UCS-Ext-B-4.txt
-IDS-UCS-Ext-B-5.txt
-IDS-UCS-Ext-B-6.txt
-IDS-JIS-X0208-1990.txt
-IDS-Daikanwa-01.txt
-IDS-Daikanwa-02.txt
-IDS-Daikanwa-03.txt
-IDS-Daikanwa-04.txt
-IDS-Daikanwa-05.txt
-IDS-Daikanwa-06.txt
-IDS-Daikanwa-07.txt
-IDS-Daikanwa-08.txt
-IDS-Daikanwa-09.txt
-IDS-Daikanwa-10.txt
-IDS-Daikanwa-11.txt
-IDS-Daikanwa-12.txt
-IDS-Daikanwa-dx.txt
-IDS-Daikanwa-ho.txt
-IDS-CBETA.txt
-".split
- def initialize()
- super
- @ids_list = IDS_LIST
- @chars = []
- @glob, @pre, @post = "#{IDS_DB_DIR}/db/*", "#{IDS_DB_DIR}/db/", ""
- dir = File.dirname(@pre)
- Dir.mkdir(dir) unless FileTest.exist?(dir)
- open_dbs()
- end
- def each_file()
- return unless block_given?
- @ids_list.each {|file|
- next if file =~ /^#/
- yield(IDS_DB_DIR+file)
- }
- end
- def each_line(file)
- open(file){|f|
- while line = f.gets
- next if line =~ /^;/ #コメントはとばす
- line.chomp!
- code, char, ids = line.split
- yield(code, char, ids)
- end
- }
- end
- def dump_text_all
- each_file {|file|
- dir = File.dirname(file) + '/../ids-new/'
- Dir.mkdir(dir) if ! FileTest.directory?(dir)
- newfile = dir + File.basename(file)
- p [file, newfile]
- open(newfile, "w"){|out|
- out.binmode.sync = true
- each_line(file){|code, ch, ids|
- char = Character.get(ch)
- ids = char.decompose
- out.print "#{code} #{ch} #{ids}\n"
- }
- }