2 # $Id: ids.rb,v 1.2 2003-11-10 08:38:12 eto Exp $
3 # Copyright (C) 2002-2003 Kouichirou Eto, All rights reserved.
4 # This is free software with ABSOLUTELY NO WARRANTY.
5 # You can redistribute it and/or modify it under the terms of the GNU GPL2.
7 $LOAD_PATH << '../../lib' if $0 == __FILE__
11 IDC_LEFT_TO_RIGHT = "⿰"
12 IDC_ABOVE_TO_BELOW = "⿱"
13 IDC_LEFT_TO_MIDDLE_AND_RIGHT = "⿲"
14 IDC_ABOVE_TO_MIDDLE_AND_BELOW = "⿳"
15 IDC_FULL_SURROUND = "⿴"
16 IDC_SURROUND_FROM_ABOVE = "⿵"
17 IDC_SURROUND_FROM_BELOW = "⿶"
18 IDC_SURROUND_FROM_LEFT = "⿷"
19 IDC_SURROUND_FROM_UPPER_LEFT = "⿸"
20 IDC_SURROUND_FROM_UPPER_RIGHT = "⿹"
21 IDC_SURROUND_FROM_LOWER_LEFT = "⿺"
24 IDC_LR = IDC_LEFT_TO_RIGHT
25 IDC_AB = IDC_ABOVE_TO_BELOW
26 IDC_LMR = IDC_LEFT_TO_MIDDLE_AND_RIGHT
27 IDC_AMB = IDC_ABOVE_TO_MIDDLE_AND_BELOW
28 IDC_FS = IDC_FULL_SURROUND
29 IDC_FA = IDC_SURROUND_FROM_ABOVE
30 IDC_FB = IDC_SURROUND_FROM_BELOW
31 IDC_FL = IDC_SURROUND_FROM_LEFT
32 IDC_FUL = IDC_SURROUND_FROM_UPPER_LEFT
33 IDC_FUR = IDC_SURROUND_FROM_UPPER_RIGHT
34 IDC_FLL = IDC_SURROUND_FROM_LOWER_LEFT
37 class IDS_TEXT_DB < DB #======================================================================
41 #IDS-UCS-Compat-Supplement.txt
50 IDS-JIS-X0208-1990.txt
71 @glob, @pre, @post = "#{IDS_DB_DIR}/db/*", "#{IDS_DB_DIR}/db/", ""
72 dir = File.dirname(@pre)
73 Dir.mkdir(dir) unless FileTest.exist?(dir)
77 return unless block_given?
78 @ids_list.each {|file|
80 yield(IDS_DB_DIR+file)
86 next if line =~ /^;/ #コメントはとばす
88 code, char, ids = line.split
89 yield(code, char, ids)
95 dir = File.dirname(file) + '/../ids-new/'
96 Dir.mkdir(dir) if ! FileTest.directory?(dir)
97 newfile = dir + File.basename(file)
99 open(newfile, "w"){|out|
100 out.binmode.sync = true
101 each_line(file){|code, ch, ids|
102 char = Character.get(ch)
104 out.print "#{code} #{ch} #{ids}\n"
111 dir = File.dirname(file) + '/../ids-error'
112 Dir.mkdir(dir) unless FileTest.exist?(dir)
113 errfile = dir + '/' + File.basename(file)
115 open(errfile, "w"){|out|
116 out.binmode.sync = true
117 each_line(file){|code, ch, ids|
118 char = Character.get(ch)
119 ids_error = char['ids-error']
120 next if ids_error.nil?
121 out.print "#{code} #{ch} #{ids} #{ids_error}\n"
128 class IDS_DB < DB #======================================================================BDB化したIDS DBを扱う
131 @dbs = CharDB.instance
134 db = IDS_TEXT_DB.instance
137 @same_ids_counter = 0
138 @good_ids_counter = 0
139 @conflict_ids_counter = 0
140 db.each_line(file){|code, ch, ids|
143 ids = "" if ids == nil
144 next if ids == "" #IDSが定義されていない場合は、さっくりと無視するべしよ。
146 charimg = Character.get(ch) #実体参照である可能性がある
148 next if code =~ /'$/ || code =~ /"$/ #大漢和番号のダッシュ付きは無視する
149 char = Character.get("&"+code+";") #code表記を元に実体参照を作って解釈する
150 if char.nil? || char.to_s == "" #うまく文字にならなかった
151 print "char == null #{char.inspect} #{code} #{ch} #{ids}\n" unless code =~ /^M-/ || code =~ /^CB/
152 #大漢和、CBETA以外の場合は、エラーメッセージ。
155 if char != charimg #code表記と文字が一致していない?
156 unless code =~ /^M-/ || code =~ /^MH-/ || code =~ /^CB/ #食い違っていて当然であるので何もしない
157 print "unknown char #{char.inspect} #{code} #{ch} #{ids}\n"
158 next #それ以外の場合はエラーメッセージをだして、次へ。
161 #next if !char.has_attribute? #isolated characterはまぎれこませない。
163 ids.de_er! #実体参照を解除する
164 next if ids == char.to_s #もし文字とまったく一緒なら、意味が無いので情報を持たない
165 next if ids.char_length == 1
167 idstree = IDS_Tree.new(ids)
168 c = idstree.check_integrity
169 c = "contains self" if ids.include?(char.to_s)
170 if c #ちょっとでもエラーがある場合は、
171 char['ids-error'] = c #エラーを記録して、データとしては保持しない
175 if char['ids'].nil? || char['ids'] == "" #元々IDSが無かった場合は、
176 char['ids'] = ids #普通に代入すればそれでいいです。
177 @good_ids_counter += 1
178 else #しかしいままでにすでにIDSが定義されていた場合は?
179 if char['ids'] == ids #新しいIDSと古いIDSが完全に一致するなら無視しましょう。
180 @same_ids_counter += 1
181 else #しかしいままでのIDSと新しいIDSが食い違った場合は?
182 @conflict_ids_counter += 1
183 # print "conflict #{char.inspect} #{code} #{ids} #{char['ids']}\n"
187 print "#{file} #{@char_counter} #{@same_ids_counter} #{@conflict_ids_counter} #{@good_ids_counter}\n"
188 CharacterFactory.instance.reset()
190 @dbs.dump_db('ids-error') #テキスト化する
191 @dbs.dump_db('ids') #テキスト化する
195 @dbs.each('ids') {|k, v|
198 h[ids] = "" if h[ids].nil?
202 h[k] = char_sort(v) #文字の順番を、よく使うっぽいものからの順番にする
204 h.delete_if {|k, v| #h[k]が""になる可能性もあるが、それはkeyとして入れないことにする。
207 print "length #{h.length}\n"
208 cdb = CodesysDB.instance
209 cdb.make_db_no_question_mark('ids', h)
210 cdb.open_db('ids') #これが無いと、dump_dbされません。
213 def char_sort(composed)
214 return composed if composed.char_length == 1
220 if char.char_id < 0xfffff #Unicodeっぽい?
226 EntityReference.each_codesys{|codesys, er_prefix, keta, numtype|
230 # p [codesys, v] if v
231 if v #EntityReferenceの順番に準拠する。
239 # p ['yokuwakaran character', ar, ar[0].inspect_all, arorg]
240 EntityReference.each_codesys{|codesys, er_prefix, keta, numtype|
244 # p [codesys, v] if v
250 def dump_ids_duplicated
251 open('ids-duplicated.txt', 'w'){|out|
253 CodesysDB.instance.each('ids') {|k, v|
255 out.print "nil #{k} #{v}\n"
260 out.print "#{n} #{k} #{v}"
263 out.print " #{char.inspect}"
269 def make_ids_aggregated
270 @dbs.each('ids') {|k, v|
274 char['ids-aggregated'] = ag
276 @dbs.dump_db('ids-aggregated')
278 def dump_ids_aggregated
279 open('ids-aggregated.txt', 'w'){|out|
281 @dbs.each('ids') {|k, v|
284 ag = char['ids-aggregated']
285 out.print "#{char.to_s} #{ag} #{ids}\n" if ids != ag
290 @dbs.each('ids') {|k, v|
297 break if ids == pids #これ以上分割できないようだったら終了〜。
300 p [char.to_s, pids, ids, ar] if 10 < counter #これは何かおかしいぞと
305 #やっぱりIDS文字も加えることにする. by eto 2003-02-05
307 # ch.char.is_ids? #IDS文字はまぎれこませない。
310 char['ids-parts'] = str
312 @dbs.dump_db('ids-parts')
314 def make_ids_contained
316 @dbs.each('ids-parts') {|k, v|
318 parts = char.ids_parts
319 parts.each_char {|ch|
321 h[ch] = [] if h[ch].nil?
324 # part['ids-contained'] = "" if part['ids-contained'].nil?
325 # part['ids-contained'] += k
331 char['ids-contained'] = v.join('')
334 @dbs.dump_db('ids-contained')
336 def make_ids_decomposed
337 @dbs.each('ids') {|k, v|
339 de= char.decompose_all
340 char['ids-decomposed'] = de
342 @dbs.dump_db('ids-decomposed')
346 class Node < Array #=======================================================木構造の中の一つの枝
347 def initialize(nodeleaf=nil, nodenum=nil)
352 original_add(@nodeleaf)
356 alias original_add <<
357 private :original_add
360 @nodenum -= 1 if @nodenum
366 ar += n.nodes if n.is_a? Node
372 class Tree #======================================================================木構造を扱う
377 @depth = 1 #stackの深さが最大になったところの値、木構造が無いときは1となる
379 def depth() @depth - 1 end
380 def add_node(nodeleaf=nil, nodenum=nil) #枝を追加
381 new_node = Node.new(nodeleaf, nodenum)
382 @stack.last << new_node
384 if @depth < @stack.length
385 @depth = @stack.length
389 def end_node() #この枝は終り
393 def add_leaf(a) #葉を追加
399 n = @stack.last.nodenum
406 n = @stack.last.nodenum
407 return nil if @root.length == 0 #no tree is good tree
408 return "unmatch leaves" if n && n != 0
409 return "extra nodes" if @root.first.is_a?(Node) && @root.length != 1
410 return "extra leaves" if @root.length != 1
423 def to_s() @root.to_s end
424 def inspect() @root.inspect end
427 class IDS_Tree < Tree #======================================================================
435 char = Character.new(ch)
437 add_node(char, ids_operator_argc(char))
444 return true if "+*".include?(obj.to_s) #テスト用ですかね
445 return true if obj.is_ids?
448 def ids_operator_argc(obj)
449 return obj.ids_operator_argc if 0 < obj.ids_operator_argc
454 return r if r #不完全がすでにわかっているならreturn
455 return "contains ques" if @str =~ /\?/ #?が含まれている?
460 class IDS #======================================================================IDSそのものを扱うclass
461 def initialize(str) #IDS文字列をうけとる。
466 def parse_x #柔軟型のParse. IDSキャラクターが前にきてなくてもよい。などなど。
470 class Counter #======================================================================
472 #counter = Counter.new(50) { exit }
489 #----------------------------------------------------------------------end.