2 # Ruby/UTF-2000 module by eto 2002-1114
8 $KCODE = 'u' #今のところこれ以外では動かない。String.splitが影響大。inspectも影響。
10 #$stdout.binmode if $debug
11 $stdout.sync = true if $debug
14 def to_a() self.split(//) end #$KCODEが設定されているので、UTF-8的な一文字づつがchにはいる
15 def each_char() to_a.each {|ch| yield ch } end
16 def char_length() to_a.length end
17 def char_at(n) to_a()[n] end
18 def char() Character.get(to_a[0]) end
19 def method_missing(mid, *args) char.method_missing(mid, *args) end
20 def char_id() char.char_id() end
21 def get_char_attribute(a) char.get_char_attribute(a) end
22 def ucs() char.ucs() end
29 #put関係、[]関係は用意しないことにした。
30 def de_er!() #EntityReferenceを取り除く
31 return self unless self =~ Regexp.new(EntityReference::REGEXP_PART) #それらしいのが無ければ何もしない
33 self.sub!(Regexp.new(Regexp.escape(er)), Character.new(er).mcs_utf8) #変換自体はCharacterにまかせる
34 return self.de_er! if self =~ Regexp.new(EntityReference::REGEXP_PART) #まだあったら再帰
37 def de_er() return self.dup.de_er!; end
39 def map_char(block = Proc.new)
40 return unless block_given?
41 return self.to_a.map {|ch| (block.call(ch)).to_s }.join("")
43 def map_char!(block = Proc.new)
44 return unless block_given?
45 self.replace(self.map_char {|ch| block.call(ch)})
47 def inspect_all() map_char {|ch| ch.char.inspect_all } end
48 def inspect_x() map_char {|ch| ch.char.inspect_x } end
50 def decompose() map_char {|ch| ch.char.decompose } end
51 def decompose!() self.replace(self.decompose); self; end
52 def decompose_all(level=nil)
53 level = 0 if level.nil?
55 p ['too many recursive', self]
59 return de.decompose_all(level+1) if de != self #なにか変化があったから再帰
62 def decompose_all!() self.replace(self.decompose_all); self; end
64 def find() #"日雲"→"曇"とかいう感じの操作
66 length = char_length()
69 ar << char.ids_contained #その文字を含んでいる漢字のリスト
81 if length == v #全部に顔を出していたら
89 db = CodesysDB.instance
90 composed = db.get('ids', self)
91 return "" if composed.nil? #なかったよと。
92 return "" if composed.char_length == 0 #なにごと?
93 return composed if composed.char_length == 1
94 composed.each_char {|ch|
96 return ch if char.has_attribute? #とりあえず最初にみつかったものを返すというヌルい仕様
99 def nu_compose_sorted()
100 db = CodesysDB.instance
101 composed = db.get('ids', self)
102 return "" if composed.nil? #なかったよと。
103 return "" if composed.char_length == 0 #なにごと?
104 return composed if composed.char_length == 1
106 composed.each_char {|ch|
108 ar << ch if char.has_attribute?
113 if char.char_id < 0xfffff #Unicodeっぽい?
118 EntityReference.each_codesys{|codesys, er_prefix, keta, numtype|
122 if v #EntityReferenceの順番に準拠する。
129 p ['yokuwakaran character', ar, ar[0].inspect_all]
135 CharDB.instance.each_sort('ids'){|k, v| #文字, IDS
144 #selfである文字列をIDSだと仮定し、それを完全にcomposeしきらないで、
145 #その部分集合だけをとりだして、compose可能であればできるだけcomposeする。
146 tree = IDS_Tree.new(self)
147 return self if tree.depth <= 1 #sub_nodesが無い場合はここでさよなら
148 tree.sub_nodes.each {|node|
150 next if c.nil? || c == ""
151 n = self.gsub(node, c)
154 return self #おきかえられるものがまったくなかったら、自分をかえす。
160 (RUBY_PLATFORM =~ /win/ || RUBY_PLATFORM =~ /mingw/)
162 module_function :windows?
164 DB_DIR = 'd:/work/chise/char-db' #この後に/sysmtem-char-id/ucsという感じに続く
166 DB_DIR = '/usr/local/lib/xemacs-21.4.10/i686-pc-linux/char-db' #この後に/sysmtem-char-id/ucsという感じに続く
169 class EntityReference #======================================================================
170 #状況によってどのERに変換するかが異なる可能性があるので、普通のclassとして実装したほうがいい?
172 %w( chinese-big5-cdp CDP- 4 X),
173 %w( ideograph-daikanwa M- 5 d),
174 %w( ideograph-cbeta CB 5 d),
175 %w( ideograph-gt GT- 5 d),
176 %w( ideograph-gt-k GT-K 5 d),
177 %w( japanese-jisx0208-1990 J90- 4 X),
178 %w( japanese-jisx0208 J83- 4 X),
179 %w( japanese-jisx0213-1 JX1- 4 X),
180 %w( japanese-jisx0213-2 JX2- 4 X),
181 %w( japanese-jisx0212 JSP- 4 X),
182 %w( japanese-jisx0208-1978 J78- 4 X),
183 %w( chinese-cns11643-1 C1- 4 X),
184 %w( chinese-cns11643-2 C2- 4 X),
185 %w( chinese-cns11643-3 C3- 4 X),
186 %w( chinese-cns11643-4 C4- 4 X),
187 %w( chinese-cns11643-5 C5- 4 X),
188 %w( chinese-cns11643-6 C6- 4 X),
189 %w( chinese-cns11643-7 C7- 4 X),
190 %w( korean-ksc5601 K0- 4 X),
192 CODESYS_ORDER = %w(japanese chinese korean ideograph)
193 REGEXP_PART = "&([-+0-9A-Za-z]+);"
194 REGEXP_ALL = "^#{REGEXP_PART}$"
196 def self.match?(er) (er =~ Regexp.new(REGEXP_PART)) != nil end
198 def self.parse(er) #char_idをFIXNUMで返す
199 return "" unless er =~ Regexp.new(REGEXP_ALL) #なんか、間違ってる?
200 er = $1 #ついでに中身の部分を取り出す
201 return $1.hex if er =~ /^MCS-([0-9A-Fa-f]+)/ #MCS
202 return $1.hex if er =~ /^U[-+]([0-9A-Fa-f]+)/ #Unicode直打ち
204 er.sub!(/^I-/, '') if er =~ /^I-/ #I-がついてるとどう違うのかはよくわからない
205 each_codesys {|codesys, er_prefix, keta, numtype| #p [codesys, er_prefix, keta, numtype]
206 numtyperegex = '\d' #if numtype == 'd'
207 numtyperegex = '[0-9A-Fa-f]' if numtype == 'X'
208 regexpstr = "^#{er_prefix}(#{numtyperegex}{#{keta},#{keta}})$" #p regexpstr
209 if er =~ Regexp.new(regexpstr)
211 code = codestr.to_i #if numtype == 'd'
212 code = codestr.hex if numtype == 'X'
213 char_id_u8 = EntityReference.get_database(codesys, code)
214 char_id_num = Character.parse_char_id(char_id_u8)
220 def self.each_codesys()
221 CODESYS_ORDER.each {|lang|
222 CODESYS_TABLE.each {|codesys, er_prefix, keta, numtype| #普通こういう書き方はしない。ループ一個にする。
223 next unless codesys =~ lang
224 yield(codesys, er_prefix, keta, numtype)
228 def self.get_database(codesys, code)
229 c = CodesysDB.instance.get(codesys, code)
231 if codesys =~ /-jisx0208/
232 #return self.get_database("=jis-x0208", code) #再帰でどうだ?
233 c = CodesysDB.instance.get("=jis-x0208", code)
240 class CharacterFactory #============================================文字オブジェクトの生成、cache
249 n = Character.parse_char_id(char_id)
251 @chars[n] = Character.new(n) if @chars[n] == nil
257 GC.start #ガーベージコレクション
259 def length() @chars.length; end
261 reset if @max < @chars.length #MAXを超えたらresetしてしまう。乱暴じゃがcacheなのでこれでいいのだ。
265 class Character #=============================================================== 文字オブジェクト
266 def initialize(char_id=nil)
267 @char_id = Character.parse_char_id(char_id)
268 @attributes = Hash.new
269 @check_all_database = false
272 def mcs_utf8() Character.u4itou8(@char_id) end
274 #----------------------------------------------------------------------
275 def self.get(char_id) CharacterFactory.instance.get(char_id) end #flyweightパターン
277 #----------------------------------------------------------------------
278 def get_char_attribute(a) # XEmacs UTF-2000互換API群
279 a.gsub!(/_/, '-') #underlineは-に置換
281 return atr if atr != nil
282 atr = check_database(a)
283 @attributes[a] = atr if atr != nil
284 return get_char_attribute("=jis-x0208") if a =~ /jisx0208/
285 return @attributes[a]
287 def put_char_attribute(a,v)
288 a.gsub!(/_/, '-') #underlineは-に置換
290 CharDB.instance.put(a, mcs_utf8(), v)
292 def char_attribute_alist() check_all_database(); @attributes; end
293 def char_attribute_list() check_all_database(); @attributes.keys; end
294 alias [] get_char_attribute #その略称
295 alias []= put_char_attribute
296 alias alist char_attribute_alist
297 alias list char_attribute_list
299 def method_missing(mid, *args) #参考:ostruct.rb
301 return get_char_attribute(mname) if args.length == 0
302 put_char_attribute(mname.chop, args[0]) if mname =~ /=$/ #代入
305 def has_attribute?() #意味のあるattributeを持ってますか?
310 return (keys.length != 0)
313 #----------------------------------------------------------------------
315 return false if ch == nil
316 return false unless ch.is_a? Character
317 self.char_id == ch.char_id
320 #----------------------------------------------------------------------
321 def self.parse_char_id(char_id) #FIXNUMを返す
322 return nil if char_id == nil
323 if char_id.is_a?(Numeric) #p [char_id]
324 char_id = 0x80000000 + char_id if char_id < 0 #補数表現
326 elsif char_id.is_a?(String)
327 return char_id.to_i if char_id =~ /^\d+$/ #文字列による数字だったら数値化してreturn
328 return EntityReference.parse(char_id) if char_id =~ Regexp.new(EntityReference::REGEXP_ALL) #実体参照?
329 char_id.sub!(/^\?/, '') if char_id =~ /^\?/ #もし先頭に?がついていたら削除
330 #このへん本当はもっとちゃんとチェックするべし
331 u4 = Uconv.u8tou4(char_id) #UCS-4文字列に変換
332 return Character.u4tou4i(u4) #UCS-4数値にしてreturn
334 raise ArgumentError, "unknown object for char_id", caller(1)
338 return 0 if u4 == nil || u4 == ""
339 return (u4[3] << 24 | u4[2] << 16 | u4[1] << 8 | u4[0]) #UCS-4数値にしてreturn
341 def self.u4itou4(num)
342 return "" if num == nil
343 return sprintf("%c%c%c%c", num&0xff, (num >> 8)&0xff, (num >> 16)&0xff, (num >> 24)&0xff) #UCS-4数値を文字列にしてreturn
345 def self.u4itou8(char_id) #ucsの数値を受けとり、UTF-8の文字一文字を返す
347 u4 = Character.u4itou4(char_id)
348 u8 = Uconv.u4tou8(u4)
351 #raise ArgumentError, "invalid char_id (#{char_id})", caller(1)
357 #----------------------------------------------------------------------
358 def check_database(a)
361 v = db.get(a, u8) #u8で表される文字のaアトリビュートを調べる。
364 def check_all_database() #現在の@char_idから、文字データベースを参照する
365 return if @check_all_database
366 return if @char_id == nil
369 atrs = db.get_all(u8) #u8で表される文字のアトリビュートを全部持ってこい
371 @attributes[a] = v #とかいう感じで代入するのでええかな?
373 @check_all_database = true #重い処理なので一応checkする
376 #----------------------------------------------------------------------
378 #ar = %w{ucs ucs-big5 ucs-cdp ucs-cns ucs-jis ucs-ks =>ucs =>ucs* =>ucs-jis}
379 ar = %w{ucs ucs-jis ucs-big5 ucs-cdp ucs-cns ucs-ks =>ucs =>ucs* =>ucs-jis}
380 #並び順は恣意的で、ucs-jisを先に出している。本来はこれも指定できるようにするべき。
382 u = get_char_attribute(a)
388 #----------------------------------------------------------------------CCS関係
389 def to_utf8() Uconv.u4tou8(Character.u4itou4(ucs())) end #UTF8文字列を返す
393 #----------------------------------------------------------------------
394 def to_er(codesys=nil) #実体参照を返す、希望するcodesysが引数(未実装)
395 return "" if @char_id == nil
396 return sprintf("&U+%04X;", @char_id) if @char_id <= 0xffff
397 return sprintf("&U-%05X;", @char_id) if @char_id <= 0xfffff
398 EntityReference.each_codesys {|codesys, er_prefix, keta, numtype|
401 return sprintf("&#{er_prefix}%0#{keta}#{numtype};", code)
403 return sprintf("&MCS-%08X;", @char_id) #本当はこれは無しにしたい
407 EntityReference.each_codesys {|codesys, er_prefix, keta, numtype|
409 ar << er if er != nil
415 return "<>" if @char_id == nil
416 ar = [to_utf8(), to_er().sub(/^&/,'').chop]
419 alias inspect inspect_x
420 def inspect_all_codesys()
421 #to_erを全てのcodesysにおいて実行する。その結果をコンパクトにまとめる
425 alist.to_a.sort.each {|a, v| ar << "#{a}:#{v}" }
426 return ar.join(',')+">"
430 alist.to_a.sort.each {|a, v|
431 str += "#{a}: #{v}\n"
436 #----------------------------------------------------------------------IDS関係
440 # return idss if idss
441 idss = self['ids-aggregated']
442 return idss if idss != nil && 0 < idss.length && k != idss
444 return idss if idss != nil && 0 < idss.length && k != idss
446 # return k if idss.nil? || idss.length == 0 || k == idss
447 # if idss.char_length == 2
448 # p ['What???', k, idss, k.inspect_all]
449 # #return idssx[1] #二個目だけ返すとか?
450 # return k #IDSに展開する方法が無いと。
452 # return k if k == idss
453 # if idss.include?(k) #<C5-4C4D><C6-4A37>この二文字のBUG対策
454 # #return idss.sub(k, '')
455 # return k #IDSに展開する方法が無いと。
459 def is_ids?() 0x2ff0 <= @char_id && @char_id <= 0x2fff end
460 def ids_operator_argc()
461 return 0 unless is_ids?
462 return 3 if @char_id == 0x2ff2 || @char_id == 0x2ff3
467 class DBS #======================================================================複数のDBを集めたclass
470 class ADB < BDB::Hash #======================================================================一つのDB
471 def initialize(*args)
476 self.close #これがないと、うまくデータベースがセーブされないのです。
480 def self.open_create(filename)
481 ADB.open(filename, nil, BDB::CREATE | BDB::EXCL) #上書きはしない
485 if key.char_length == 1
486 return '?'+key #Stringだったら引く前に?を足す
489 #key = key.to_s if key.is_a?(Numeric) #NumberだったらStringにする。
490 #ここで && key ! =~ /^\?/ をいれると、?自身を検索できなくなってしまう。
495 return v.to_i if v =~ /^\d+$/ #数字だったらここで変換しておく
496 return v.sub(/^\?/, '') if v =~ /^\?/ #冒頭の?は取り除く
497 return $1 if v =~ /^"(.+)"$/ #最初と最後に"がついていたら、取り除く
498 #p ['get', v, t, key, db]
499 #return parse_sexp(v) if v =~ /^\(.+\)$/ #最初と最後が()の時は、S式にparseする
502 def myget(key) #keyキーを引いて返す
504 v = get(key) #存在しなかったらnilを返すことになる
507 def myput(key, v) #keyにvをいれる
514 class DB #======================================================= データベース群のabstract class
515 def self.unix_to_win(unix) #Windowsファイル名制限のため、変換する
516 win = unix.gsub(/</, '(')
522 def self.win_to_unix(win)
523 unix = win.gsub(%r|\)|, '>')
524 unix.gsub!(%r|\(|, '<')
525 unix.gsub!(%r|!|, '?')
526 unix.gsub!(%r|\+|, '*')
529 # def windows?() DB.windows?() end
531 return @pre + DB.unix_to_win(t) + @post if windows?
532 return @pre + t + @post
534 def get_dirname(t) File.dirname(get_filename(t)) end
538 keys.each {|key| open_db(key) }
543 next if ! File.file?(f)
549 t = DB.win_to_unix(f)
550 t.sub!(%r|^#{@pre}|, '')
551 t.sub!(%r|#{@post}$|, '') if @post != ""
559 return nil if db.nil?
564 return nil if get(t) #すでにopenしていたら再openはしない。
566 bdb = ADB.open(get_filename(t), nil, 0)
567 @dbs[t] = bdb if bdb != nil
569 p ["open error", get_filename(t)]; return nil
573 def make_db(t, h=nil) #tという名前でhという中身のデータベースを作る
574 return nil if get(t) #すでにある場合はreturn
575 Dir.mkdir(get_dirname(t)) unless FileTest.exist?(get_dirname(t))
578 db = ADB.open_create(get_filename(t)) #上書きはしない
581 k = '?'+k if k.is_a?(String)
587 p ["make error", get_filename(t)]; return nil
591 def make_db_no_question_mark(t, h=nil) #tという名前でhという中身のデータベースを作る
592 return nil if get(t) #すでにある場合はreturn
593 Dir.mkdir(get_dirname(t)) unless FileTest.exist?(get_dirname(t))
596 db = ADB.open_create(get_filename(t)) #上書きはしない
599 # k = '?'+k if k.is_a?(String)
605 p ["make error", get_filename(t)]; return nil
609 def remove_db(t) #tという名前のデータベースを消去する
616 File.unlink(get_filename(t)) if FileTest.file?(get_filename(t))
618 p ["unlink error", get_filename(t)]; return nil
621 Dir.rmdir(dn) if FileTest.directory?(dn) && Dir.entries(dn).length <= 2 #空directoryだったら消す
625 return s.to_i if s =~ /^\d+$/
631 file = get_filename(t)
632 open("#{file}.txt", "w"){|out|
633 # out.binmode.sync = true
635 ar.map! {|k, v| [to_num(k), to_num(v)] }
637 out.printf("%s\t%s\n", k, v)
642 def each_db() @dbs.to_a.sort.each {|t, db| yield(t, db) } end
643 def dump_all() each_db {|t, db| dump_db(t) } end
644 def close_all() each_db {|t, db| db.close } end
645 def keys() @dbs.keys end
647 return unless block_given?
653 k.sub!(/^\?/, '') if k =~ /^\?/ #冒頭の?は取り除く
654 vv = get(t, k) #p ['each', t, k, v, vv]
659 return unless block_given?
663 ar.map! {|k, v| [to_num(k), to_num(v)] }
665 k.sub!(/^\?/, '') if k =~ /^\?/ #冒頭の?は取り除く
666 vv = get(t, k) #p ['each', t, k, v, vv]
670 #----------------------------------------------------------------------
671 def get(t, key=nil) #tというデータベースのkeyキーを引いて返す
673 return db if key.nil?
677 def put(t, key, v) #tというデータベースのkeyにvをいれる
684 db.myput(key, v) #putする
688 class CharDB < DB #------------------------------------ MCS-UTF8をキーとした属性へのデータベース
692 @glob, @pre, @post = "#{DB_DIR}/system-char-id/*", "#{DB_DIR}/system-char-id/", ""
695 def get_all(u8) #全データベースのu8キーを引いてHashにまとめて返す
699 atrs[t] = v if v != nil
705 class CodesysDB < DB #----------------------------------------------------------------------
709 @glob, @pre, @post = "#{DB_DIR}/*/system-char-id", "#{DB_DIR}/", "/system-char-id"
712 #def keys() @dbs.keys.sort end #どんなCodesysの情報を持っているかの一覧
713 def keys() @dbs.keys end #どんなCodesysの情報を持っているかの一覧
717 return Codesys.new(t)
721 class Codesys < DB #======================================================================
725 @dbs = CodesysDB.instance
727 def keys() #どんなコードポイントの情報を持っているかの一覧
728 ks = @dbs.get(@name).keys
729 if @name =~ /jisx0208/ #特別処理
730 n = @dbs.get('=jis-x0208').keys
731 # p ['keys', @name, ks, n]
734 ks.map! {|k| to_num(k) }
738 v = @dbs.get(@name, key)
740 if @name =~ /jisx0208/ #jisx0208が含まれている場合だけ特別処理する
741 return @dbs.get('=jis-x0208', key)
746 return unless block_given?
752 k.sub!(/^\?/, '') if k =~ /^\?/ #冒頭の?は取り除く
753 vv = @dbs.get(@name, k) #p ['each', t, k, v, vv]
758 return unless block_given?
762 ar.map! {|k, v| [to_num(k), to_num(v)] }
764 k.sub!(/^\?/, '') if k =~ /^\?/ #冒頭の?は取り除く
765 vv = @dbs.get(@name, k) #p ['each', t, k, v, vv]
771 class IDS_TEXT_DB < DB #======================================================================
774 IDS_DB_DIR = 'd:/work/chise/ids/' #この後にIDS-JIS-X0208-1990.txtという感じに続く
776 IDS_DB_DIR = '/home/eto/work/chise/ids/' #この後にIDS-JIS-X0208-1990.txtという感じに続く
779 IDS-JIS-X0208-1990.txt
796 #IDS-UCS-Compat-Supplement.txt
810 @glob, @pre, @post = "#{IDS_DB_DIR}/db/*", "#{IDS_DB_DIR}/db/", ""
811 dir = File.dirname(@pre)
812 Dir.mkdir(dir) unless FileTest.exist?(dir)
816 return unless block_given?
817 @ids_list.each {|file|
819 yield(IDS_DB_DIR+file)
825 next if line =~ /^;/ #コメントはとばす
827 code, char, ids = line.split
828 yield(code, char, ids)
834 dir = File.dirname(file) + '/../ids-new/'
835 Dir.mkdir(dir) if ! FileTest.directory?(dir)
836 newfile = dir + File.basename(file)
838 open(newfile, "w"){|out|
839 out.binmode.sync = true
840 each_line(file){|code, ch, ids|
841 char = Character.get(ch)
843 out.print "#{code} #{ch} #{ids}\n"
850 dir = File.dirname(file) + '/../ids-error'
851 Dir.mkdir(dir) unless FileTest.exist?(dir)
852 errfile = dir + '/' + File.basename(file)
854 open(errfile, "w"){|out|
855 out.binmode.sync = true
856 each_line(file){|code, ch, ids|
857 char = Character.get(ch)
858 ids_error = char['ids-error']
859 next if ids_error.nil?
860 out.print "#{code} #{ch} #{ids} #{ids_error}\n"
867 class IDS_DB < DB #======================================================================BDB化したIDS DBを扱う
870 @dbs = CharDB.instance
873 db = IDS_TEXT_DB.instance
875 db.each_line(file){|code, ch, ids|
876 char = Character.get(ch) #実体参照である
877 ids = "" if ids == nil
878 ids.de_er! #実体参照を解除する
879 char['ids-text'] = ids
881 p [file, CharacterFactory.instance.length]
882 CharacterFactory.instance.reset()
884 @dbs.dump_db('ids-text') #テキスト化する
886 def make_ids_error_check
887 @dbs.each('ids-text') {|k, ids|
888 next if k.nil? || k == "" || ids.nil? || ids == "" #無視します
889 next if k == ids #問題無しなので
891 idstree = IDS_Tree.new(ids)
892 c = idstree.check_integrity
893 c = "contains self" if ids.include?(k)
894 c = "no attribute" if !char.has_attribute? #isolated characterはまぎれこませない。
896 char['ids-error'] = c
900 # print c,"\t", k.char.to_er,"\t", k,"\t", v,"\n"
902 @dbs.dump_db('ids-error') #テキスト化する
903 @dbs.dump_db('ids') #テキスト化する
907 @dbs.each('ids') {|k, v|
910 h[ids] = "" if h[ids].nil?
914 h[k] = char_sort(v) #文字の順番を、よく使うっぽいものからの順番にする
916 h.delete_if {|k, v| #h[k]が""になる可能性もあるが、それはkeyとして入れないことにする。
919 p ['length', h.length]
920 cdb = CodesysDB.instance
921 cdb.make_db_no_question_mark('ids', h)
924 def char_sort(composed)
925 return composed if composed.char_length == 1
931 if char.char_id < 0xfffff #Unicodeっぽい?
937 EntityReference.each_codesys{|codesys, er_prefix, keta, numtype|
941 # p [codesys, v] if v
942 if v #EntityReferenceの順番に準拠する。
950 # p ['yokuwakaran character', ar, ar[0].inspect_all, arorg]
951 EntityReference.each_codesys{|codesys, er_prefix, keta, numtype|
955 # p [codesys, v] if v
961 def dump_ids_duplicated
962 open('ids-duplicated.txt', 'w'){|out|
964 CodesysDB.instance.each('ids') {|k, v|
966 out.print "nil #{k} #{v}\n"
971 out.print "#{n} #{k} #{v}"
974 out.print " #{char.inspect}"
980 def make_ids_aggregated
981 @dbs.each('ids') {|k, v|
985 char['ids-aggregated'] = ag
987 @dbs.dump_db('ids-aggregated')
989 def dump_ids_aggregated
990 open('ids-aggregated.txt', 'w'){|out|
992 @dbs.each('ids') {|k, v|
995 ag = char['ids-aggregated']
996 out.print "#{char.to_s} #{ag} #{ids}\n" if ids != ag
1001 @dbs.each('ids') {|k, v|
1007 ids = pids.decompose
1008 break if ids == pids #これ以上分割できないようだったら終了〜。
1011 p [char.to_s, pids, ids, ar] if 10 < counter #これは何かおかしいぞと
1016 #やっぱりIDS文字も加えることにする. by eto 2003-02-05
1017 # ar.delete_if {|ch|
1018 # ch.char.is_ids? #IDS文字はまぎれこませない。
1021 char['ids-parts'] = str
1023 @dbs.dump_db('ids-parts')
1025 def make_ids_contained
1027 @dbs.each('ids-parts') {|k, v|
1029 parts = char.ids_parts
1030 parts.each_char {|ch|
1032 h[ch] = [] if h[ch].nil?
1035 # part['ids-contained'] = "" if part['ids-contained'].nil?
1036 # part['ids-contained'] += k
1042 char['ids-contained'] = v.join('')
1045 @dbs.dump_db('ids-contained')
1047 def make_ids_decomposed
1048 @dbs.each('ids') {|k, v|
1050 de= char.decompose_all
1051 char['ids-decomposed'] = de
1053 @dbs.dump_db('ids-decomposed')
1057 class Node < Array #=======================================================木構造の中の一つの枝
1058 def initialize(nodeleaf=nil, nodenum=nil)
1060 @nodeleaf = nodeleaf
1063 original_add(@nodeleaf)
1066 attr_reader :nodenum
1067 alias original_add <<
1068 private :original_add
1071 @nodenum -= 1 if @nodenum
1077 ar += n.nodes if n.is_a? Node
1083 class Tree #======================================================================木構造を扱う
1088 @depth = 1 #stackの深さが最大になったところの値、木構造が無いときは1となる
1090 def depth() @depth - 1 end
1091 def add_node(nodeleaf=nil, nodenum=nil) #枝を追加
1092 new_node = Node.new(nodeleaf, nodenum)
1093 @stack.last << new_node
1095 if @depth < @stack.length
1096 @depth = @stack.length
1100 def end_node() #この枝は終り
1104 def add_leaf(a) #葉を追加
1110 n = @stack.last.nodenum
1117 n = @stack.last.nodenum
1118 return nil if @root.length == 0 #no tree is good tree
1119 return "unmatch leaves" if n && n != 0
1120 return "extra nodes" if @root.first.is_a?(Node) && @root.length != 1
1121 return "extra leaves" if @root.length != 1
1134 def to_s() @root.to_s end
1135 def inspect() @root.inspect end
1138 class IDS_Tree < Tree #======================================================================
1145 @str.each_char {|ch|
1146 char = Character.new(ch)
1148 add_node(char, ids_operator_argc(char))
1155 return true if "+*".include?(obj.to_s) #テスト用ですかね
1156 return true if obj.is_ids?
1159 def ids_operator_argc(obj)
1160 return obj.ids_operator_argc if 0 < obj.ids_operator_argc
1165 return r if r #不完全がすでにわかっているならreturn
1166 return "contains ques" if @str =~ /\?/ #?が含まれている?
1172 class IDS #======================================================================IDSそのものを扱うclass
1173 def initialize(str) #IDS文字列をうけとる。
1178 def parse_x #柔軟型のParse. IDSキャラクターが前にきてなくてもよい。などなど。
1182 class Counter #======================================================================
1184 #counter = Counter.new(50) { exit }
1201 #----------------------------------------------------------------------終了