1 # Copyright (C) 2002-2004 Kouichirou Eto, All rights reserved.
3 $LOAD_PATH << "../../lib" if $0 == __FILE__
7 # IDC_LEFT_TO_RIGHT = "⿰"
8 # IDC_ABOVE_TO_BELOW = "⿱"
9 # IDC_LEFT_TO_MIDDLE_AND_RIGHT = "⿲"
10 # IDC_ABOVE_TO_MIDDLE_AND_BELOW = "⿳"
11 # IDC_FULL_SURROUND = "⿴"
12 # IDC_SURROUND_FROM_ABOVE = "⿵"
13 # IDC_SURROUND_FROM_BELOW = "⿶"
14 # IDC_SURROUND_FROM_LEFT = "⿷"
15 # IDC_SURROUND_FROM_UPPER_LEFT = "⿸"
16 # IDC_SURROUND_FROM_UPPER_RIGHT = "⿹"
17 # IDC_SURROUND_FROM_LOWER_LEFT = "⿺"
20 IDC_LEFT_TO_RIGHT = "\342\277\260" #2FF0
21 IDC_ABOVE_TO_BELOW = "\342\277\261"
22 IDC_LEFT_TO_MIDDLE_AND_RIGHT = "\342\277\262"
23 IDC_ABOVE_TO_MIDDLE_AND_BELOW = "\342\277\263"
24 IDC_FULL_SURROUND = "\342\277\264" #2FF4
25 IDC_SURROUND_FROM_ABOVE = "\342\277\265"
26 IDC_SURROUND_FROM_BELOW = "\342\277\266"
27 IDC_SURROUND_FROM_LEFT = "\342\277\267"
28 IDC_SURROUND_FROM_UPPER_LEFT = "\342\277\270"
29 IDC_SURROUND_FROM_UPPER_RIGHT = "\342\277\271"
30 IDC_SURROUND_FROM_LOWER_LEFT = "\342\277\272"
31 IDC_OVERLAID = "\342\277\273"
33 IDC_LR = IDC_LEFT_TO_RIGHT
34 IDC_AB = IDC_ABOVE_TO_BELOW
35 IDC_LM = IDC_LEFT_TO_MIDDLE_AND_RIGHT
36 IDC_AM = IDC_ABOVE_TO_MIDDLE_AND_BELOW
37 IDC_FS = IDC_FULL_SURROUND
38 IDC_FA = IDC_SURROUND_FROM_ABOVE
39 IDC_FB = IDC_SURROUND_FROM_BELOW
40 IDC_FL = IDC_SURROUND_FROM_LEFT
41 IDC_UL = IDC_SURROUND_FROM_UPPER_LEFT
42 IDC_UR = IDC_SURROUND_FROM_UPPER_RIGHT
43 IDC_LL = IDC_SURROUND_FROM_LOWER_LEFT
53 class IDS_TEXT_DB < DB #======================================================================
57 #IDS-UCS-Compat-Supplement.txt
66 IDS-JIS-X0208-1990.txt
88 @dir = Config.instance.ids_dir
90 @glob, @pre, @post = "#{@dir}/db/*", "#{@dir}/db/", ""
91 dir = File.dirname(@pre)
92 Dir.mkdir(dir) unless FileTest.exist?(dir)
97 return unless block_given?
98 @ids_list.each {|file|
107 next if line =~ /^;/ #コメントはとばす
109 code, char, ids = line.split
110 yield(code, char, ids)
116 dir = File.dirname(file) + "/../ids-new/"
117 Dir.mkdir(dir) if ! FileTest.directory?(dir)
118 newfile = dir + File.basename(file)
120 open(newfile, "w"){|out|
121 out.binmode.sync = true
122 each_line(file){|code, ch, ids|
123 char = Character.get(ch)
125 out.print "#{code} #{ch} #{ids}\n"
132 dir = File.dirname(file) + "/../ids-error"
133 Dir.mkdir(dir) unless FileTest.exist?(dir)
134 errfile = dir + "/" + File.basename(file)
136 open(errfile, "w"){|out|
137 out.binmode.sync = true
138 each_line(file){|code, ch, ids|
139 char = Character.get(ch)
140 ids_error = char["ids-error"]
141 next if ids_error.nil?
142 out.print "#{code} #{ch} #{ids} #{ids_error}\n"
149 class IDS_DB < DB # BDB化したIDS DBを扱う
152 @dbs = CharDB.instance
155 db = IDS_TEXT_DB.instance
158 @same_ids_counter = 0
159 @good_ids_counter = 0
160 @conflict_ids_counter = 0
161 db.each_line(file){|code, ch, ids|
164 ids = "" if ids == nil
165 next if ids == "" #IDSが定義されていない場合は、さっくりと無視するべしよ。
167 charimg = Character.get(ch) #実体参照である可能性がある
169 next if code =~ /'$/ || code =~ /"$/ #大漢和番号のダッシュ付きは無視する
170 char = Character.get("&"+code+";") #code表記を元に実体参照を作って解釈する
171 if char.nil? || char.to_s == "" #うまく文字にならなかった
172 print "char == null #{char.inspect} #{code} #{ch} #{ids}\n" unless code =~ /^M-/ || code =~ /^CB/
173 #大漢和、CBETA以外の場合は、エラーメッセージ。
176 if char != charimg #code表記と文字が一致していない?
177 unless code =~ /^M-/ || code =~ /^MH-/ || code =~ /^CB/ #食い違っていて当然であるので何もしない
178 print "unknown char #{char.inspect} #{code} #{ch} #{ids}\n"
179 next #それ以外の場合はエラーメッセージをだして、次へ。
182 #next if !char.has_attribute? #isolated characterはまぎれこませない。
184 ids.de_er! #実体参照を解除する
185 next if ids == char.to_s #もし文字とまったく一緒なら、意味が無いので情報を持たない
186 next if ids.char_length == 1
188 idstree = IDS_Tree.new(ids)
189 c = idstree.check_integrity
190 c = "contains self" if ids.include?(char.to_s)
191 if c #ちょっとでもエラーがある場合は、
192 char["ids-error"] = c #エラーを記録して、データとしては保持しない
196 if char["ids"].nil? || char["ids"] == "" #元々IDSが無かった場合は、
197 char["ids"] = ids #普通に代入すればそれでいいです。
198 @good_ids_counter += 1
199 else #しかしいままでにすでにIDSが定義されていた場合は?
200 if char["ids"] == ids #新しいIDSと古いIDSが完全に一致するなら無視しましょう。
201 @same_ids_counter += 1
202 else #しかしいままでのIDSと新しいIDSが食い違った場合は?
203 @conflict_ids_counter += 1
204 # print "conflict #{char.inspect} #{code} #{ids} #{char["ids"]}\n"
208 print "#{file} #{@char_counter} #{@same_ids_counter} #{@conflict_ids_counter} #{@good_ids_counter}\n"
209 CharacterFactory.instance.reset()
211 @dbs.dump_db("ids-error") #テキスト化する
212 @dbs.dump_db("ids") #テキスト化する
216 @dbs.each("ids") {|k, v|
219 h[ids] = "" if h[ids].nil?
223 h[k] = char_sort(v) #文字の順番を、よく使うっぽいものからの順番にする
225 h.delete_if {|k, v| #h[k]が""になる可能性もあるが、それはkeyとして入れないことにする。
228 print "length #{h.length}\n"
229 cdb = CodesysDB.instance
230 cdb.make_db_no_question_mark("ids", h)
231 cdb.open_db("ids") #これが無いと、dump_dbされません。
234 def char_sort(composed)
235 return composed if composed.char_length == 1
241 if char.char_id < 0xfffff #Unicodeっぽい?
247 EntityReference.each_codesys{|codesys, er_prefix, keta, numtype|
251 # p [codesys, v] if v
252 if v #EntityReferenceの順番に準拠する。
260 # p ["yokuwakaran character", ar, ar[0].inspect_all, arorg]
261 EntityReference.each_codesys{|codesys, er_prefix, keta, numtype|
265 # p [codesys, v] if v
271 def dump_ids_duplicated
272 open("ids-duplicated.txt", "w"){|out|
274 CodesysDB.instance.each("ids") {|k, v|
276 out.print "nil #{k} #{v}\n"
281 out.print "#{n} #{k} #{v}"
284 out.print " #{char.inspect}"
290 def make_ids_aggregated
291 @dbs.each("ids") {|k, v|
295 char["ids-aggregated"] = ag
297 @dbs.dump_db("ids-aggregated")
299 def dump_ids_aggregated
300 open("ids-aggregated.txt", "w"){|out|
302 @dbs.each("ids") {|k, v|
305 ag = char["ids-aggregated"]
306 out.print "#{char.to_s} #{ag} #{ids}\n" if ids != ag
311 @dbs.each("ids") {|k, v|
318 break if ids == pids #これ以上分割できないようだったら終了〜。
321 p [char.to_s, pids, ids, ar] if 10 < counter #これは何かおかしいぞと
326 #やっぱりIDS文字も加えることにする. by eto 2003-02-05
328 # ch.char.is_ids? #IDS文字はまぎれこませない。
331 char["ids-parts"] = str
333 @dbs.dump_db("ids-parts")
335 def make_ids_contained
337 @dbs.each("ids-parts") {|k, v|
339 parts = char.ids_parts
340 parts.each_char {|ch|
342 h[ch] = [] if h[ch].nil?
345 # part["ids-contained"] = "" if part["ids-contained"].nil?
346 # part["ids-contained"] += k
352 char["ids-contained"] = v.join("")
355 @dbs.dump_db("ids-contained")
357 def make_ids_decomposed
358 @dbs.each("ids") {|k, v|
360 de= char.decompose_all
361 char["ids-decomposed"] = de
363 @dbs.dump_db("ids-decomposed")
367 class Node < Array #==================================木構造の中の一つの枝
368 def initialize(nodeleaf=nil, nodenum=nil)
373 original_add(@nodeleaf)
377 alias original_add <<
378 private :original_add
381 @nodenum -= 1 if @nodenum
387 ar += n.nodes if n.is_a? Node
393 class Tree #==================================================木構造を扱う
398 @depth = 1 #stackの深さが最大になったところの値、木構造が無いときは1となる
400 def depth() @depth - 1 end
401 def add_node(nodeleaf=nil, nodenum=nil) #枝を追加
402 new_node = Node.new(nodeleaf, nodenum)
403 @stack.last << new_node
405 if @depth < @stack.length
406 @depth = @stack.length
410 def end_node() #この枝は終り
414 def add_leaf(a) #葉を追加
420 n = @stack.last.nodenum
427 n = @stack.last.nodenum
428 return nil if @root.length == 0 #no tree is good tree
429 return "unmatch leaves" if n && n != 0
430 return "extra nodes" if @root.first.is_a?(Node) && @root.length != 1
431 return "extra leaves" if @root.length != 1
444 def to_s() @root.to_s end
445 def inspect() @root.inspect end
448 class IDS_Tree < Tree
456 char = Character.new(ch)
458 add_node(char, ids_operator_argc(char))
465 return true if "+*".include?(obj.to_s) #テスト用ですかね
466 return true if obj.is_ids?
469 def ids_operator_argc(obj)
470 return obj.ids_operator_argc if 0 < obj.ids_operator_argc
475 return r if r #不完全がすでにわかっているならreturn
476 return "contains ques" if @str =~ /\?/ #?が含まれている?
481 class IDS #=========================================IDSそのものを扱うclass
482 def initialize(str) #IDS文字列をうけとる。
487 def parse_x #柔軟型のParse. IDSキャラクターが前にきてなくてもよい。などなど。
493 #counter = Counter.new(50) { exit }