mymatrix 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in mymatrix.gemspec
4
+ gemspec
data/Rakefile CHANGED
@@ -1,26 +1 @@
1
- require 'rubygems'
2
- gem 'hoe', '>= 2.1.0'
3
- require 'hoe'
4
- require 'fileutils'
5
- require './lib/mymatrix'
6
-
7
- Hoe.plugin :newgem
8
- # Hoe.plugin :website
9
- # Hoe.plugin :cucumberfeatures
10
-
11
- # Generate all the Rake tasks
12
- # Run 'rake -T' to see list of generated tasks (from gem root directory)
13
- $hoe = Hoe.spec 'mymatrix' do
14
- self.developer 'zucay', 'yukihico@gmail.com'
15
-
16
- self.rubyforge_name = self.name # TODO this is default value
17
- # self.extra_deps = [['activesupport','>= 2.0.2']]
18
-
19
- end
20
-
21
- require 'newgem/tasks'
22
- Dir['tasks/**/*.rake'].each { |t| load t }
23
-
24
- # TODO - want other tests/tasks run by default? Add them to the list
25
- # remove_task :default
26
- # task :default => [:spec, :features]
1
+ require "bundler/gem_tasks"
data/lib/mymatrix.rb CHANGED
@@ -1,1235 +1,1238 @@
1
- #!/usr/bin/ruby -Ku
2
- # -*- encoding: utf-8 -*-
3
-
4
- $:.unshift(File.dirname(__FILE__)) unless
5
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
6
-
7
- require 'rubygems'
8
- require 'spreadsheet'
9
- require 'nkf'
10
- require 'logger'
11
- require 'pp'
12
- require 'enumerable_ex' #verbose_each
13
-
14
- if(RUBY_VERSION =~ /1\.[^9]/)
15
- $KCODE='UTF8'
16
- end
17
-
18
- class MyMatrix
19
- VERSION = '0.0.1'
20
-
21
- attr_accessor :file, :internal_lf, :mx
22
- include Enumerable
23
- #to_t()の際のセパレータ。
24
- SEPARATOR = "\t"
25
-
26
- # コンストラクタ
27
- # ====Args
28
- # _file_ :: オープンするファイル。
29
- # ====Return
30
- # 生成されたMyMatrixオブジェクト
31
- def initialize(file=nil, opts={})
32
- #platform check
33
- if(RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|cygwin|bccwin/)
34
- $mymatrix_filesystem = 's'
35
- elsif(RUBY_PLATFORM.downcase =~ /darwin/)
36
- $mymatrix_filesystem = 'm'
37
- elsif(RUBY_PLATFORM.downcase =~ /linux/)
38
- $mymatrix_filesystem = 'u'
39
- else
40
- $mymatrix_filesystem = 'u'
41
- end
42
-
43
-
44
-
45
- #内部改行コード。
46
- @internal_lf = '<br>'
47
- rnd = rand(9999)
48
- i = 0
49
- begin
50
- @log = Logger.new("MyMatrix_ERR_#{i}.log")
51
- rescue
52
- i += 1
53
- retry
54
- end
55
- @log.level = Logger::DEBUG
56
- @file = file
57
-
58
- @mx = []
59
- if(@file =~ /\.xls$/)
60
- @mx = makeMatrixFromXLS(@file, opts)
61
- elsif(@file =~ /(\.tsv|\.txt|\.TSV|\.TXT)/)
62
- @mx = makeMatrixFromTSV(@file, opts)
63
- elsif(@file =~ /(\.csv|\.CSV)/)
64
- #opts[:sep] = ','
65
- #@mx = makeMatrixFromTSV(@file, opts)
66
- @mx = makeMatrixFromCSV(@file, opts)
67
-
68
- # elsif(@file =~ /\.mmx$/)
69
- # readmx = Marshal.load(open(@file).read)
70
- # return readmx
71
- elsif(@file == nil)
72
- else
73
- #デフォルトはTSVで読み込むようにする。
74
- @mx = makeMatrixFromTSV(@file, opts)
75
- end
76
-
77
- #@mxの末尾に空レコードが入っていたら、その空白を削除
78
- while(@mx[@mx.size-1] && @mx[@mx.size-1].join == '')
79
- @mx.pop
80
- end
81
- if(@mx.size == 0)
82
- @mx = []
83
- end
84
- @headers = @mx.shift
85
- registerMatrix
86
- return self
87
- end
88
-
89
- # CP932を正しく扱うための変換関数
90
- # ====Args
91
- # _str_ :: UTF8文字列
92
- # ====Return
93
- # CP932の文字列
94
- def self.tosjis(str)
95
- str = MyMatrix.cp932ize(str)
96
- if(RUBY_VERSION =~ /1\.[^9]/)
97
- #-xは半角カナを全角にするのを抑止するオプション。
98
- out = NKF.nkf('-W -x -s --cp932', str)
99
- else
100
- out = str.encode("Windows-31J")
101
- end
102
-
103
-
104
- return out
105
- end
106
- # 外部ファイルエンコード(CP932)を内部エンコード(UTF8)に変換する
107
- # ====Args
108
- # _str_:: CP932 string
109
- # ====Return
110
- # UTF8 String
111
- def self.toutf8(str)
112
- #out = NKF.nkf('-x -w --cp932', str)
113
- #入力がShift-jisであるとする。
114
- out = NKF.nkf('-S -x -w --cp932', str)
115
- return out
116
- end
117
-
118
- # MacOSXのファイルシステムで使われるUTF8-Mac(BOMつきUTF)に変換する
119
- def self.toUtf8Mac(str)
120
- out = str
121
- return out
122
- end
123
- # ファイルオープン時、パス文字列のエンコードを変換してシステムに返却するためのメソッド
124
- def encodePath(path)
125
- case $mymatrix_filesystem
126
- when 'u'
127
- #utf8=>utf8なので何もしない
128
- #path = MyMatrix.toutf8(path)
129
- #path.encode('UTF-8')
130
- path
131
- when 's'
132
- path = MyMatrix.tosjis(path)
133
- #path.encode('Windows-31J')
134
- when 'w'
135
- path = MyMatrix.tosjis(path)
136
- #path.encode('Windows-31J')
137
- when 'm'
138
- path = MyMatrix.toUtf8Mac(path)
139
- end
140
- end
141
-
142
- #--
143
- #protected methods
144
- #++
145
- protected
146
- # 現在のヘッダ@headersに合わせてハッシュ@headerHを生成する
147
- # @headersを書き換えた場合に必ず実行するメソッド
148
- def registerMatrix
149
- @headerH = Hash.new
150
- if(!@headers)
151
- @headers = []
152
- end
153
- @headers.each_with_index do |colName, i|
154
- @headerH[colName] = i
155
- end
156
- fillEmptyCell
157
- end
158
-
159
- # ヘッダ@headers を書き換えた場合など、@headers.sizeとrow.sizeが異なる場合にサイズを揃え
160
- # 空文字列を入れておく。getValue()した際に必ずStringを返却するための処理。
161
- # ====※rowを伸ばす方向のみ。@headersを短くした場合の動作は保証できない!
162
- #
163
- def fillEmptyCell
164
- headerSize = getHeaders.size
165
- @mx.each_with_index do |row, i|
166
- if(row.size < headerSize)
167
- (headerSize - row.size).times do |i|
168
- row << ''
169
- end
170
- elsif(row.size > headerSize)
171
- warn("row is large:#{@file} line #{i+2} / rowSize #{row.size} / headersize #{headerSize}")
172
- #raise "rowsize error"
173
- end
174
- end
175
- end
176
- # xls読み込みメソッド
177
- def makeMatrixFromXLS(xlsFile, opts={})
178
- if(opts)
179
- offset = opts[:offset]
180
- end
181
- offset ||= 0
182
-
183
- out = []
184
- #todo xlsFileがなかったら作成
185
- encodePath(xlsFile)
186
- xl = Spreadsheet.open(encodePath(xlsFile), 'rb')
187
- sheet = xl.worksheet(0)
188
- rowsize = sheet.last_row_index
189
- (rowsize+1-offset).times do |i|
190
- row = sheet.row(i+offset)
191
- orow = []
192
- row.each do |ele|
193
- #様々な型で値が入っている。改行も入っている
194
- if(ele.class == Float)&&(ele.to_s =~ /(\d+)\.0/)
195
- ele = $1
196
- end
197
- if(ele.class == Spreadsheet::Formula)
198
- ele = ele.value
199
- end
200
- if(ele == nil)
201
- ele = ''
202
- end
203
- ele = ele.to_s.gsub(/\n/, '<br>')
204
- orow << ele
205
- end
206
- out << orow
207
- end
208
-
209
- return out
210
- end
211
- #TSV: tab separated value 読み込みメソッド
212
- def makeMatrixFromTSV(file, opts={:sep=>SEPARATOR, :offset=>0})
213
- out = []
214
- epath = encodePath(file)
215
- if(!File.exist?(epath))
216
- open(epath, 'w') do |fo|
217
- fo.print("\n\n")
218
- end
219
- end
220
- #fi = open(file.encode('Windows-31J'), "r:Windows-31J")
221
- fi = open(encodePath(file), "r:Windows-31J")
222
- if(opts[:offset])
223
- opts[:offset].times do |i|
224
- fi.gets
225
- end
226
- end
227
- opts[:sep]||=SEPARATOR
228
- fi.each do |line|
229
- row = MyMatrix.toutf8(line).chomp.split(/#{opts[:sep]}/)
230
- #「1,300台」などカンマが使われている場合、「"1,300台"」となってしまうので、カンマを無視する
231
- newRow = []
232
- row.each do |cell|
233
- stri = cell.dup
234
- stri.gsub!(/^\"(.*)\"$/, '\1')
235
- #"
236
- stri.gsub!(/""/, '"')
237
- newRow << stri
238
- end
239
- out << newRow
240
- end
241
- fi.close
242
- return out
243
- end
244
-
245
- #CSV読み込みメソッド
246
- def makeMatrixFromCSV(file, opts={:offset=>0})
247
- #1.9系ではFasterCSVを使えない
248
- if(RUBY_VERSION =~ /1\.[^9]/)
249
- #1.8以下の場合
250
- require 'fastercsv'
251
- csv = FasterCSV
252
- else
253
- #1.9以上の場合
254
- require 'csv'
255
- Encoding.default_external = 'Windows-31J'
256
- csv = CSV
257
- end
258
- out = []
259
- i= 0
260
- syspath = encodePath(file)
261
- csv.foreach(syspath, {:row_sep => "\r\n", :encoding => 'Shift_JIS'}) do |row|
262
- if(opts[:offset])
263
- if(opts[:offset] < i)
264
- next
265
- end
266
- end
267
- #「1,300台」などカンマが使われている場合、「"1,300台"」となってしまうので、カンマを無視する
268
- newRow = []
269
- row.each do |cell|
270
- cell = cell.to_s
271
- cell ||= ''
272
- cell = MyMatrix.toutf8(cell)
273
- #cell = cell.gsub(/^\"/, "")
274
- #cell = cell.gsub(/\"$/, "")
275
- #"
276
- newRow << cell
277
- end
278
- out << newRow
279
- i += 1
280
- end
281
- return out
282
- end
283
-
284
- def isEnd(row)
285
- out = true
286
- row.each do |cell|
287
- if(cell != "")
288
- out = nil
289
- break
290
- end
291
- end
292
- return out
293
- end
294
-
295
- public
296
- # カラムの値を配列で返却する
297
- def getColumn(colName)
298
- out = []
299
- @mx.each do |row|
300
- begin
301
- out << getValue(row, colName)
302
- rescue
303
- raise "#{colName} notfound: #{row}"
304
- end
305
- end
306
- return out
307
- end
308
-
309
- # getColumn のエイリアスメソッド
310
- def getValues(colName)
311
- return getColumn(colName)
312
- end
313
- #カラムの値を複数指定して、多次元配列を返却するメソッド。
314
- def getColumns(colNames)
315
- out = []
316
- colNames.each do |colName|
317
- out << getColumn(colName)
318
- end
319
- return out
320
- end
321
-
322
- #
323
- def getColumnsByMatrix(colNames)
324
- out = MyMatrix.new
325
- colNames.each do |colName|
326
- col = getColumn(colName)
327
- out.addColumn(colName, col)
328
- end
329
- return out
330
- end
331
- def val(row, str)
332
- getValue(row, str)
333
- end
334
-
335
- def getValue(row, str)
336
- out = nil
337
- index = @headerH[str]
338
- if(index)
339
- out = row[index]
340
- #お尻のセルでNULLの場合などは、nilが返却されてしまう。なので、''となるようにする。
341
- if(!out)
342
- out = ''
343
- end
344
- #参照を渡さないためdupする
345
- out = out.dup
346
- else
347
- raise "header not found:#{str} file:#{@file}"
348
- end
349
- return out
350
- end
351
- alias val getValue
352
- =begin
353
- def getValues(row, arr)
354
- out = []
355
- arr.each do |ele|
356
- out << getValue(row, ele)
357
- end
358
- if(out.size == 0)
359
- out = nil
360
- end
361
- return out
362
- end
363
- =end
364
- def setValue(row, str, value)
365
- if(!row)
366
- raise 'row is nil'
367
- end
368
- index = @headerH[str]
369
- if(!index)
370
- addHeaders([str])
371
- end
372
- #参照先の値も変更できるように、破壊メソッドを使う。row[@headerH[str]] = valueでは、参照先が切り替わってしまうので、値の置き換えにならない。
373
- #findなどで取得したrowに対して処理を行う際に必要な変更。
374
- if(row[@headerH[str]].class == String)
375
- row[@headerH[str]].sub!(/^.*$/, value)
376
- else
377
- #raise('not string error.')
378
- #todo 強烈なバグな気もするが、例外を回避し値を代入2010年12月15日
379
- begin
380
- row[@headerH[str]] = value.to_s
381
- rescue
382
- row[@headerH[str]] = ''
383
- end
384
- end
385
- end
386
- def each
387
- @mx.each do |row|
388
- yield(row)
389
- end
390
- end
391
- #未検証
392
- def reverse
393
- out = empty
394
-
395
- @mx.reverse.each do |row|
396
- out << row
397
- end
398
- return out
399
- end
400
-
401
-
402
- def size
403
- return @mx.size
404
- end
405
- def [](i,j)
406
- return @mx[i][j]
407
- end
408
-
409
- def [](i)
410
- return @mx[i]
411
- end
412
-
413
- #未検証
414
- def +(other)
415
- out = MyipcMatrix.new
416
-
417
- othHeaders = other.getHeaders
418
- selHeaders = getHeaders
419
-
420
- selHeaders.each do |header|
421
- out.addColumn(header, getColumn(header))
422
- end
423
-
424
- othHeaders.each do |header|
425
- out.addColumn(header, other.getColumn(header))
426
- end
427
-
428
- return out
429
- end
430
-
431
- def addColumn(header, column)
432
- pushColumn(header, column)
433
- end
434
- def <<(row)
435
- addRow(row)
436
- end
437
- def addRow(row)
438
- if(row.class != Array)
439
- row = [row]
440
- end
441
- row.size.times do |i|
442
- if(row[i] == nil)
443
- row[i] = ''
444
- end
445
- end
446
-
447
- headerSize = getHeaders.size
448
- rowSize = row.size
449
- if(headerSize > rowSize)
450
- (headerSize - rowSize).times do |i|
451
- row << ''
452
- end
453
- elsif(rowSize > headerSize)
454
- raise("row size error. headerSize:#{headerSize} rowSize:#{rowSize}")
455
- end
456
- @mx << row.dup
457
- end
458
- def [](i)
459
- return @mx[i]
460
- end
461
- def []=(key, value)
462
- @mx[key] = value
463
- end
464
-
465
- def pushColumn(header, column)
466
- colPos = @headers.length
467
- @headers << header
468
- registerMatrix
469
- column.each_with_index do |cell, i|
470
- if(@mx[i] == nil)
471
- @mx[i] = []
472
- end
473
- @mx[i][colPos] = cell
474
- end
475
- end
476
- #使い勝手が良くないので気をつけて使う(todo参照)
477
- def unShiftColumn(header, column)
478
- @headers.unshift(header)
479
- registerMatrix
480
- column.each_with_index do |cell, i|
481
- if(@mx[i] == nil)
482
- @mx[i] = []
483
- end
484
- #todo:ヘッダよりでかいrowがある場合バグる。期待していない一番右の値が取れてしまう。
485
- @mx[i].unshift(cell)
486
- end
487
- end
488
-
489
- def shiftColumn()
490
- header = @headers.shift
491
- column = []
492
- registerMatrix
493
- @mx.each do |row|
494
- column << row.shift
495
- end
496
- return header, column
497
- end
498
-
499
- #複数に分割されたテキストファイルを出力する
500
- def divide(splitNum)
501
- lineNum = (@mx.size / splitNum) + 1
502
- mymxs = []
503
- tmp = MyMatrix.new
504
- tmp.file = @file
505
- tmp.addHeaders(getHeaders)
506
- @mx.each_with_index do |row, i|
507
- tmp << row.dup
508
- if((i+1) % lineNum == 0)
509
- mymxs << tmp
510
- tmp = MyMatrix.new
511
- tmp.addHeaders(getHeaders)
512
- tmp.file = @file
513
- end
514
- end
515
- mymxs << tmp
516
- mymxs.each_with_index do |mymx, i|
517
- p i
518
- mymx.to_t_with("#{i}")
519
- end
520
- end
521
- #ファイルの中身をSJISにするために使ってる
522
- def localEncode(v, enc = 's')
523
- case enc
524
- when 'u'
525
- str = MyMatrix.toutf8(v)
526
- when 's'
527
- str = MyMatrix.tosjis(v)
528
- else
529
- str = MyMatrix.tosjis(v)
530
- end
531
- end
532
- #使い方はto_t()を参照。yield。
533
- def to_text(outFile)
534
- outFile = encodePath(outFile)
535
- out = []
536
- out << @headers
537
- @mx.each do |row|
538
- out << row
539
- end
540
- begin
541
- fo = open(outFile, 'wb')
542
- rescue => e
543
- p "cannot write file...#{outFile}"
544
- p e
545
- sleep(5)
546
- retry
547
- end
548
- out.each_with_index do |row, i|
549
- if(row == nil)
550
- warn("line #{i} is nil")
551
- fo.print("")
552
- else
553
- str = yield(row)
554
- fo.print(str)
555
- end
556
- fo.print("\r\n")
557
- end
558
- fo.close
559
- end
560
- # テキスト出力する
561
- def to_t(outFile=nil, opts={})
562
- if(!outFile)
563
- outFile = @file
564
- end
565
-
566
- #拡張子の判別
567
- ext = File.extname(outFile).downcase
568
- case ext
569
- when '.csv'
570
- opts[:separator] ||= ','
571
- opts[:escape] ||= true
572
- when '.xls'
573
- p 'use Tab-Separated-Value text format.'
574
- outFile = outFile + '.txt'
575
- when '.xlsx'
576
- p 'use Tab-Separated-Value text format.'
577
- outFile = outFile + '.txt'
578
- else
579
- #do nothing
580
- end
581
- #デフォルトオプションの設定
582
- opts[:enc] ||= 's'
583
- opts[:escape] ||= false
584
- opts[:separator] ||= SEPARATOR
585
-
586
- to_text(outFile) do |row|
587
- orow = []
588
- if(opts[:escape])
589
- row.each do |cell|
590
- orow << myescape(cell)
591
- end
592
- else
593
- row.each do |cell|
594
- orow << cell.to_s.gsub(/[#{opts[:separator]}\r\n]/, '')
595
- end
596
- end
597
-
598
- begin
599
- str = localEncode(orow.join(opts[:separator]), opts[:enc])
600
- rescue Encoding::UndefinedConversionError
601
- orow.each do |ele|
602
- begin
603
- localEncode(ele, opts[:enc])
604
- rescue
605
- raise "encode error.#{ele}\n(#{orow})"
606
- end
607
- end
608
-
609
- @log.debug(row.join(opts[:separator]))
610
- end
611
- str
612
- end
613
- end
614
- def myescape(cell)
615
- o = cell.to_s.dup
616
- o.gsub!(/"/, '""')
617
- if o =~ /[",']/
618
- #'
619
- o = "\"#{o}\""
620
- end
621
- return o
622
- end
623
- # 読み込んだファイル名にpostfixを付与してテキストファイル出力する
624
- def to_t_with(postfix="out", opts={})
625
- opath = MyMatrix.make_path(@file, {:ext=>nil, :postfix=>postfix})
626
- to_t(opath, opts)
627
- return opath
628
- end
629
-
630
- #CSV出力する。ダブルクオーテーションやカンマをエスケープする。
631
- def to_csv(outFile)
632
- to_t(outFile, {:separator=>',', :escape=>true})
633
- end
634
-
635
- #ヘッダのコピーを返却する
636
- def getHeaders
637
- out = @headers.dup
638
- return out
639
- end
640
- #ヘッダを置き換える
641
- def replaceHeader(before, after)
642
- @headers[@headerH[before]] = after
643
- registerMatrix
644
- end
645
-
646
- # colNameの値がvalueの行のうち先頭のものを返却する。todo:名称がよくない。
647
- def index(colName, value)
648
- out = nil
649
- col = getColumn(colName)
650
- col.each_with_index do |cell, i|
651
- if(value == cell)
652
- out = i
653
- break
654
- end
655
- end
656
- return out
657
- end
658
-
659
- # colnameの値がvalueの行のもののインデックス値を配列で返却する。todo:名称がよくない。
660
- def searchIndexes(colName, value)
661
- out = []
662
- col = getColumn(colName)
663
- col.each_with_index do |cell, i|
664
- if(value == cell)
665
- out << i
666
- end
667
- end
668
- return out
669
- end
670
-
671
- # colnameの値がvalueの行のrowを配列で返却する。todo:名称がよくない。
672
- def search(colName, value)
673
- indexes = []
674
- col = getColumn(colName)
675
- col.each_with_index do |cell, i|
676
- if(value == cell)
677
- indexes << i
678
- end
679
- end
680
- out = self.empty
681
- indexes.each do |index|
682
- out << @mx[index]
683
- end
684
- return out
685
- end
686
- # ヘッダを追加する(配列)
687
- def addHeaders(aheaders)
688
- @headers.concat(aheaders).uniq!
689
-
690
- registerMatrix
691
- end
692
-
693
- # ヘッダを追加する
694
- def addHeader(key)
695
- addHeaders([key])
696
- end
697
-
698
- #行数を返却する
699
- def size
700
- return @mx.size
701
- end
702
-
703
- #未検証。「要素の重複判定は、Object#eql? により行われます。」http://www.ruby-lang.org/ja/old-man/html/Array.html#uniq
704
- def uniq!
705
- @mx.uniq!
706
- end
707
-
708
- def shift
709
- return @mx.shift
710
- end
711
- def unshift(var)
712
- return @mx.unshift(var)
713
- end
714
- def pop
715
- return @mx.pop
716
- end
717
- def push(var)
718
- return @mx.push(var)
719
- end
720
- def delete_at(pos)
721
- @mx.delete_at(pos)
722
- end
723
-
724
- #未検証。「要素を順番にブロックに渡して評価し、その結果が真になった要素を すべて削除します。」
725
- def delete_if
726
- out = @mx.delete_if do |row|
727
- yield(row)
728
- end
729
- @mx = out
730
- end
731
- def delete(v)
732
- @mx.delete(v)
733
- end
734
- #ブロックがTrueになる、配列(参照)を返却するメソッド
735
- def find
736
- #todo rowsを返却するのと、Mymatrxixを返却するのとどっちがイイのか。。
737
- rows = []
738
- @mx.each do |row|
739
- if(yield(row))
740
- rows << row.dup
741
- end
742
- end
743
- return rows
744
- end
745
-
746
- #headersに記載の
747
- def select(headers)
748
- out = self.class.new
749
- headers.each do |header|
750
- out.addColumn(header, getColumn(header))
751
- end
752
- out.file = @file
753
- return out
754
- end
755
-
756
- #fromColName => toColNameのハッシュを作成する。
757
- #fromColNameの値が同じだとtoColNameが上書きされるので使いにくいと思われる。
758
- def makeHash(fromColName, toColName)
759
- out = Hash.new
760
- @mx.each do |row|
761
- from = getValue(row, fromColName)
762
- to = getValue(row, toColName)
763
- out[from] = to
764
- end
765
- return out
766
- end
767
-
768
- #colnameがキーのハッシュを作る。valueはrowの配列。
769
- def makeKey(colname)
770
- out = {}
771
- self.each do |row|
772
- key = self.val(row, colname)
773
- if(out[key] == nil)
774
- out[key] = []
775
- end
776
- out[key] << row
777
- end
778
- return out
779
- end
780
-
781
- #MyipcMatrixとの互換性のため。getValueのエイリアス
782
- def getCrrValue(row, str)
783
- p 'this class is not MyipcMatrix.'
784
- getValue(row, str)
785
- end
786
-
787
- def concatCells(headers, colname)
788
- addHeaders([colname])
789
- @mx.each do |row|
790
- val = []
791
- headers.each do |header|
792
- val << getValue(row, header)
793
- end
794
- setValue(row, colname, val.join('_').gsub(/_+/, '_'))
795
- end
796
- end
797
-
798
- #読み込んだファイルのパスを返却する
799
- def getPath
800
- return @file
801
- end
802
- #ファイルパスを設定する。 to_tを引数なしで使うと、設定したパスにファイルが生成される。
803
- def setPath(path)
804
- @file = path
805
- end
806
-
807
- # strを含む(/#{str}/)ヘッダ名を配列で返却する。
808
- def searchHeader(str)
809
- out = []
810
- getHeaders.each do |header|
811
- if(header =~ /#{str}/)
812
- out << header
813
- end
814
- end
815
- end
816
-
817
- #n分割した配列を返却する
818
- def devide(n)
819
- out = []
820
- mx = @mx.dup
821
- eleSize = mx.size/n
822
- n.times do |i|
823
- o = self.empty
824
- eleSize.times do |j|
825
- o << mx.shift
826
- end
827
- out << o
828
- end
829
- #@mx.size%n分余ってるので、追加
830
- mx.each do |ele|
831
- out[n-1] << ele
832
- end
833
- return out
834
- end
835
- #compareHeaderの値の中に、valuesに書かれた値があったら、targetHeaderにフラグを立てる
836
- def addFlg(targetHeader, compareHeader, values, flgValue='1')
837
- compares = getColumn(compareHeader)
838
- values.each do|value|
839
- i = compares.index(value)
840
- if(i)
841
- setValue(@mx[i], targetHeader, flgValue)
842
- else
843
- #raise "VALUE NOT FOUND:#{value}"
844
- end
845
- end
846
- end
847
-
848
- def without(regexp_or_string)
849
- if(regexp_or_string.class == String)
850
- regexp = /#{regexp_or_string}/
851
- else
852
- regexp = regexp_or_string
853
- end
854
- newHeaders = []
855
- @headers.each do |header|
856
- if(header =~ regexp)
857
- else
858
- newHeaders << header
859
- end
860
- end
861
- out = select(newHeaders)
862
- return out
863
- end
864
-
865
- #行が空(ヘッダはそのまま)のコピーを返却する
866
- def empty
867
- out = self.dup
868
- out.empty!
869
- return out
870
- end
871
-
872
- #selfの行を空にする
873
- def empty!
874
- @mx = []
875
- return self
876
- end
877
- def fill(rows)
878
- rows.each do |row|
879
- self << row
880
- end
881
- return self
882
- end
883
-
884
- #行番号を付与する
885
- def with_serial(headerName = 'No.')
886
- out = self.empty
887
- out.addHeaders([headerName], 1)
888
- self.each_with_index do |row, i|
889
- no = i + 1
890
- newRow = [no].concat(row)
891
- out << newRow
892
- end
893
- return out
894
- end
895
-
896
-
897
- def count(header, value)
898
- out = 0
899
- arr = getColumn(header)
900
- arr.each do |ele|
901
- if(ele =~ /#{value}/)
902
- out += 1
903
- end
904
- end
905
- return out
906
- end
907
- #全件カウントして、[value, count] という配列に格納する
908
- def countup(header)
909
- out = []
910
- values = getColumn(header).uniq
911
- values.each do |value|
912
- out << [value, self.count(header, value)]
913
- end
914
- return out
915
- end
916
- def getDoubles(arr)
917
- doubles = arr.select do |e|
918
- arr.index(e) != arr.rindex(e)
919
- end
920
- doubles.uniq!
921
- return doubles
922
- end
923
-
924
- def filter(header, value)
925
- out = empty
926
- @mx.each do|row|
927
- v = getValue(row, header)
928
- if(v == value)
929
- out << row
930
- end
931
- end
932
- return out
933
- end
934
- #配列と引き算とかする際に使われる。
935
- def to_ary
936
- arr = []
937
- @mx.each do |row|
938
- #arr << row.dup
939
- arr << row
940
- end
941
- return arr
942
- end
943
- def to_s
944
- out = ''
945
- @mx.each do |row|
946
- out = out + row.to_s + "\n"
947
- end
948
- return out
949
- end
950
- def to_s_with_header
951
- out = self.getHeaders.to_s + "\n"
952
- out = out + self.to_s
953
- end
954
- def concat(mx, opt={})
955
- notfoundHeaders = []
956
- mx.each do |row|
957
- o = []
958
- mx.getHeaders.each do |head|
959
- begin
960
- self.setValue(o, head, mx.getValue(row, head))
961
- rescue => e
962
- #p e
963
- if(opt[:loose]==true)
964
- self.addHeaders([head])
965
- #p "#{head} added"
966
- retry
967
- else
968
- notfoundHeaders << head
969
- end
970
- end
971
- end
972
- self << o
973
- end
974
- if(notfoundHeaders.size > 0)
975
- raise "notfoundHeader : #{notfoundHeaders.uniq.join(',')}"
976
- end
977
- return self
978
- end
979
- def concatFile(file, opt={})
980
- #p file
981
- mx = MyMatrix.new(file)
982
- self.concat(mx, opt)
983
- return self
984
- end
985
- #フォルダ内ファイルの結合。絶対パスを指定する
986
- def concatDir(dir)
987
- dir = File.expand_path(dir)
988
- Dir.entries(dir).each do |ent|
989
- if(ent =~ /^\./)
990
- else
991
- #p ent
992
-
993
- file = dir + '/' + ent
994
- #p "concat:#{file}"
995
- nmx = MyMatrix.new(file)
996
- self.concat(nmx)
997
- end
998
- end
999
-
1000
- end
1001
- =begin
1002
- def concat!(mx)
1003
- o = self.concat(mx)
1004
- self = o
1005
- return self
1006
- end
1007
- def concatFile!(file)
1008
- o = self.concatFile(file)
1009
- self = o
1010
- return self
1011
- end
1012
- =end
1013
- def flushCol(colname)
1014
- @mx.each do |row|
1015
- self.setValue(row, colname, '')
1016
- end
1017
- return self
1018
- end
1019
- def sortBy(colname, reverse=false)
1020
- sortmx = []
1021
- self.each do |row|
1022
- key = self.getValue(row, colname)
1023
- sortmx << [key, row]
1024
- end
1025
- sortmx.sort!
1026
- self.empty!
1027
- sortmx.each do |keyrow|
1028
- self << keyrow[1]
1029
- end
1030
- return self
1031
- end
1032
- def dupRow(row, destmx, destrow, headers)
1033
- headers.each do |head|
1034
- val = self.getValue(row, head)
1035
- destmx.setValue(destrow, head, val)
1036
- end
1037
- return destrow
1038
- end
1039
- def setSame(head, headValue, hash)
1040
- idxs = self.searchIndexes(head, headValue)
1041
- idxs.each do |idx|
1042
- hash.each_pair do |key, value|
1043
- self.setValue(@mx[idx], key, value)
1044
- end
1045
- end
1046
- end
1047
-
1048
- #都道府県市区町村コードの桁そろえ
1049
- #Excelで先頭の0が落ちて桁が変わるため
1050
- def correctCityCodes!(colname = '都道府県市区町村コード')
1051
- self.each do |row|
1052
- code = self.val(row, colname)
1053
- if(code.length == 4)
1054
- self.setValue(row, colname, sprintf("%05d", code))
1055
- elsif(code.length == 5)
1056
- #correct
1057
- else
1058
- raise "Citycode length error. '#{code}'"
1059
- end
1060
- end
1061
- return self
1062
- end
1063
-
1064
- #末尾空白の削除
1065
- def delEndSp!
1066
- self.each do |row|
1067
- self.getHeaders.each do |head|
1068
- val = self.val(row, head)
1069
- if(val =~ /(.*)[  ]$/)
1070
- self.setValue(row, head, $1)
1071
- end
1072
- end
1073
- end
1074
- return self
1075
- end
1076
- #半角カタカナの全角化
1077
- def twoByteKana!
1078
- self.each do |row|
1079
- self.getHeaders.each do |head|
1080
- val = self.val(row, head)
1081
- #if(val =~ /[-~]/)
1082
- if(val =~ /[]/)
1083
- #p "#{self.file} #{val}"
1084
- next
1085
- end
1086
- #nval = Kconv.kconv(val, Kconv::UTF8, Kconv::UTF8)
1087
- #nval = NKF.nkf('-W -w -x --cp932', val)
1088
-
1089
- nval = NKF.nkf('-W -w', val)
1090
-
1091
- if(val!=nval)
1092
- #p "#{val}=>#{nval}"
1093
- end
1094
- self.setValue(row, head, nval)
1095
- end
1096
- end
1097
- return self
1098
- end
1099
- def self.cp932ize(str)
1100
- out = str.dup
1101
- cases = [
1102
- #['−', '―'], #MINUS SIGN(U+2212) to FULLWIDTH HYPHEN-MINUS(U+2015)(windows)
1103
- #↑仕様としては上記が正しいが、運用上MINUS SIGN(U+2212) は FULLWIDTH HYPHEN-MINUS(U+FF0D)に変換する
1104
- #キー入力時にMacとWindowsで同じ文字コードとなることが望ましいため。
1105
-
1106
- ['〜','~'], #WAVE DASH (U+301C) to FULLWIDTH TILDE(U+FF5E)(windows)
1107
- ['‖','∥'], #DOUBLE VERTICAL LINE (U+2016, "‖") を PARALLEL TO (U+2225, "∥") に
1108
- ['', ''], #EM DASH (U+2014, "—") HORIZONTAL BAR (U+2015, "―")
1109
- #以下、キー入力を想定した変換。
1110
- ['', ''], #MacのハイフンF7(google ime)→Windows(googleime):同じ
1111
- ['ー', 'ー'], #MacのハイフンF8(google ime)→Windows(googleime):同じ
1112
- ['', ''], #MacのハイフンF9[−](google ime)→Windows[-](googleime):違う。MINUS SIGN(U+2212) to FULLWIDTH HYPHEN-MINUS(U+FF0D)
1113
- ['-', '-'], #MacのハイフンF10(google ime)→Windows(googleime):同じ
1114
- #ユニコード固有文字:ノーブレークスペース
1115
- ['[\u00A0]', ' '],
1116
- #yen
1117
- ['[\u00A5]', ''],
1118
- # éとè:eの上に´と`
1119
- ['[\u00E9]', 'e'],['[\u00E8]', 'e'],
1120
- #spaces
1121
- ['[\u2000]', ' '],['[\u2001]', ' '],['[\u2002]', ' '],['[\u2003]', ' '],['[\u2004]', ' '],['[\u2005]', ' '],['[\u2006]', ' '],['[\u2007]', ' '],['[\u2008]', ' '],['[\u2009]', ' '],['[\u200A]', ' '],['[\u205F]', ' ']
1122
- ]
1123
- cases.each do |c|
1124
- out.gsub!(/#{c[0]}/, c[1])
1125
- end
1126
- return out
1127
- end
1128
- # def save(file)
1129
- # p Marshal.dump(self)
1130
- # open(file, 'w') do |fo|
1131
- # fo.write(Marshal.dump(self))
1132
- # end
1133
- # end
1134
-
1135
- =begin
1136
- def to_xls(opts)
1137
- if(opts[:out] =~ /.xls$/)
1138
- else
1139
- raise "not outfile"
1140
- end
1141
- opts[:template] ||= opts[:out]
1142
-
1143
- opts[:offset_r] ||= 0
1144
- opts[:offset_c] ||= 0
1145
-
1146
- xl = Spreadsheet.open(encodePath(opts[:template]), 'r')
1147
- sheet = xl.worksheet(0)
1148
- @headers.each_with_index do |head, i|
1149
- ab_row = opts[:offset_r]
1150
- ab_col = opts[:offset_c] + i
1151
- sheet[ab_row, ab_col] = head
1152
- end
1153
- self.each_with_index do |row, i|
1154
- row.each_with_index do |cell, j|
1155
- ab_row = opts[:offset_r] + i + 1
1156
- #↑ヘッダ分1オフセット
1157
- ab_col = opts[:offset_c] + j
1158
- sheet[ab_row, ab_col] = cell
1159
- end
1160
- end
1161
-
1162
- xl.write(opts[:out])
1163
-
1164
- end
1165
- =end
1166
- #Arrayっぽく使うためのメソッド。内部の@mx.first
1167
- def first
1168
- @mx[0]
1169
- end
1170
- #Arrayっぽく使うためのメソッド。内部の@mx.last
1171
- def last
1172
- out = @mx[self.size-1]
1173
- end
1174
- def empty?
1175
- @mx.empty?
1176
- end
1177
- #num文字以上の項目をnum文字に丸める
1178
- def cutOff(head, num)
1179
- self.each do |row|
1180
- v = self.val(row, head)
1181
- if(v =~ /(.{#{num}})/)
1182
- self.setValue(row, head, $1)
1183
- end
1184
- end
1185
- end
1186
- def self.make_path(path, opts={ })
1187
- # opath = makepath(@file, {:ext=>nil, :postfix=>postfix})
1188
- dir = File.dirname(path)
1189
- ext = opts[:ext]
1190
- ext ||= File.extname(path)
1191
- postfix = opts[:postfix].to_s
1192
-
1193
- basename = File.basename(path, ".*")
1194
- opath = (MyMatrix.new.encodePath("#{dir}/#{basename}_#{postfix}#{ext}"))
1195
- end
1196
- end
1197
-
1198
- #ruby -Ks で利用する場合。ruby1.9では使えないはず。obsolete
1199
- class SjisMyMatrix < MyMatrix
1200
- def getValue(row, col)
1201
- col = MyMatrix.toutf8(col)
1202
- MyMatrix.tosjis(super(row, col))
1203
- end
1204
- def setValue(row, col, value)
1205
- col = MyMatrix.toutf8(col)
1206
- value = MyMatrix.toutf8(value)
1207
- super(row, col, value)
1208
- end
1209
- def addHeaders(hs)
1210
- arr =[]
1211
- hs.each do |ele|
1212
- arr << MyMatrix.toutf8(ele)
1213
- end
1214
- super(arr)
1215
- end
1216
- def getHeaders
1217
- out = []
1218
- arr = super()
1219
- arr.each do |ele|
1220
- out << MyMatrix.tosjis(ele)
1221
- end
1222
- return out
1223
- end
1224
- end
1225
-
1226
-
1227
- #rails で使う場合。obsolete
1228
- class MyRailsMatrix < MyMatrix
1229
- def headers2db(t)
1230
- getHeaders.each do |header|
1231
- t.column header, :string
1232
- end
1233
- end
1234
- end
1235
-
1
+ #!/usr/bin/ruby -Ku
2
+ # -*- encoding: utf-8 -*-
3
+ require "mymatrix/version"
4
+
5
+ $:.unshift(File.dirname(__FILE__)) unless
6
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
7
+
8
+ require 'rubygems'
9
+ require 'spreadsheet'
10
+ require 'nkf'
11
+ require 'logger'
12
+ require 'pp'
13
+ require 'enumerable_ex' #verbose_each
14
+
15
+ if(RUBY_VERSION =~ /1\.[^9]/)
16
+ $KCODE='UTF8'
17
+ end
18
+
19
+ class MyMatrix
20
+ # VERSION = '0.0.1'
21
+
22
+ attr_accessor :file, :internal_lf, :mx
23
+ include Enumerable
24
+ #to_t()の際のセパレータ。
25
+ SEPARATOR = "\t"
26
+
27
+ # コンストラクタ
28
+ # ====Args
29
+ # _file_ :: オープンするファイル。
30
+ # ====Return
31
+ # 生成されたMyMatrixオブジェクト
32
+ def initialize(file=nil, opts={})
33
+ #platform check
34
+ if(RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|cygwin|bccwin/)
35
+ $mymatrix_filesystem = 's'
36
+ elsif(RUBY_PLATFORM.downcase =~ /darwin/)
37
+ $mymatrix_filesystem = 'm'
38
+ elsif(RUBY_PLATFORM.downcase =~ /linux/)
39
+ $mymatrix_filesystem = 'u'
40
+ else
41
+ $mymatrix_filesystem = 'u'
42
+ end
43
+
44
+
45
+
46
+ #内部改行コード。
47
+ @internal_lf = '<br>'
48
+ rnd = rand(9999)
49
+ i = 0
50
+ begin
51
+ @log = Logger.new("MyMatrix_ERR_#{i}.log")
52
+ rescue
53
+ i += 1
54
+ retry
55
+ end
56
+ @log.level = Logger::DEBUG
57
+ @file = file
58
+
59
+ @mx = []
60
+ if(@file =~ /\.xls$/)
61
+ @mx = makeMatrixFromXLS(@file, opts)
62
+ elsif(@file =~ /(\.tsv|\.txt|\.TSV|\.TXT)/)
63
+ @mx = makeMatrixFromTSV(@file, opts)
64
+ elsif(@file =~ /(\.csv|\.CSV)/)
65
+ #opts[:sep] = ','
66
+ #@mx = makeMatrixFromTSV(@file, opts)
67
+ @mx = makeMatrixFromCSV(@file, opts)
68
+
69
+ # elsif(@file =~ /\.mmx$/)
70
+ # readmx = Marshal.load(open(@file).read)
71
+ # return readmx
72
+ elsif(@file == nil)
73
+ else
74
+ #デフォルトはTSVで読み込むようにする。
75
+ @mx = makeMatrixFromTSV(@file, opts)
76
+ end
77
+
78
+ #@mxの末尾に空レコードが入っていたら、その空白を削除
79
+ while(@mx[@mx.size-1] && @mx[@mx.size-1].join == '')
80
+ @mx.pop
81
+ end
82
+ if(@mx.size == 0)
83
+ @mx = []
84
+ end
85
+ @headers = @mx.shift
86
+ registerMatrix
87
+ return self
88
+ end
89
+
90
+ # CP932を正しく扱うための変換関数
91
+ # ====Args
92
+ # _str_ :: UTF8文字列
93
+ # ====Return
94
+ # CP932の文字列
95
+ def self.tosjis(str)
96
+ if(RUBY_VERSION =~ /1\.[^9]/)
97
+ #-xは半角カナを全角にするのを抑止するオプション。
98
+ out = NKF.nkf('-W -x -s --cp932', str)
99
+ else
100
+ str = MyMatrix.cp932ize(str)
101
+ out = str.encode("Windows-31J")
102
+ end
103
+
104
+
105
+ return out
106
+ end
107
+ # 外部ファイルエンコード(CP932)を内部エンコード(UTF8)に変換する
108
+ # ====Args
109
+ # _str_:: CP932 string
110
+ # ====Return
111
+ # UTF8 String
112
+ def self.toutf8(str)
113
+ #out = NKF.nkf('-x -w --cp932', str)
114
+ #入力がShift-jisであるとする。
115
+ out = NKF.nkf('-S -x -w --cp932', str)
116
+ return out
117
+ end
118
+
119
+ # MacOSXのファイルシステムで使われるUTF8-Mac(BOMつきUTF)に変換する
120
+ def self.toUtf8Mac(str)
121
+ out = str
122
+ return out
123
+ end
124
+ # ファイルオープン時、パス文字列のエンコードを変換してシステムに返却するためのメソッド
125
+ def encodePath(path)
126
+ case $mymatrix_filesystem
127
+ when 'u'
128
+ #utf8=>utf8なので何もしない
129
+ #path = MyMatrix.toutf8(path)
130
+ #path.encode('UTF-8')
131
+ path
132
+ when 's'
133
+ path = MyMatrix.tosjis(path)
134
+ #path.encode('Windows-31J')
135
+ when 'w'
136
+ path = MyMatrix.tosjis(path)
137
+ #path.encode('Windows-31J')
138
+ when 'm'
139
+ path = MyMatrix.toUtf8Mac(path)
140
+ end
141
+ end
142
+
143
+ #--
144
+ #protected methods
145
+ #++
146
+ protected
147
+ # 現在のヘッダ@headersに合わせてハッシュ@headerHを生成する
148
+ # @headersを書き換えた場合に必ず実行するメソッド
149
+ def registerMatrix
150
+ @headerH = Hash.new
151
+ if(!@headers)
152
+ @headers = []
153
+ end
154
+ @headers.each_with_index do |colName, i|
155
+ @headerH[colName] = i
156
+ end
157
+ fillEmptyCell
158
+ end
159
+
160
+ # ヘッダ@headers を書き換えた場合など、@headers.sizeとrow.sizeが異なる場合にサイズを揃え
161
+ # 空文字列を入れておく。getValue()した際に必ずStringを返却するための処理。
162
+ # ====※rowを伸ばす方向のみ。@headersを短くした場合の動作は保証できない!
163
+ #
164
+ def fillEmptyCell
165
+ headerSize = getHeaders.size
166
+ @mx.each_with_index do |row, i|
167
+ if(row.size < headerSize)
168
+ (headerSize - row.size).times do |i|
169
+ row << ''
170
+ end
171
+ elsif(row.size > headerSize)
172
+ warn("row is large:#{@file} line #{i+2} / rowSize #{row.size} / headersize #{headerSize}")
173
+ #raise "rowsize error"
174
+ end
175
+ end
176
+ end
177
+ # xls読み込みメソッド
178
+ def makeMatrixFromXLS(xlsFile, opts={})
179
+ if(opts)
180
+ offset = opts[:offset]
181
+ end
182
+ offset ||= 0
183
+
184
+ out = []
185
+ #todo xlsFileがなかったら作成
186
+ encodePath(xlsFile)
187
+ xl = Spreadsheet.open(encodePath(xlsFile), 'rb')
188
+ sheet = xl.worksheet(0)
189
+ rowsize = sheet.last_row_index
190
+ (rowsize+1-offset).times do |i|
191
+ row = sheet.row(i+offset)
192
+ orow = []
193
+ row.each do |ele|
194
+ #様々な型で値が入っている。改行も入っている
195
+ if(ele.class == Float)&&(ele.to_s =~ /(\d+)\.0/)
196
+ ele = $1
197
+ end
198
+ if(ele.class == Spreadsheet::Formula)
199
+ ele = ele.value
200
+ end
201
+ if(ele == nil)
202
+ ele = ''
203
+ end
204
+ ele = ele.to_s.gsub(/\n/, '<br>')
205
+ orow << ele
206
+ end
207
+ out << orow
208
+ end
209
+
210
+ return out
211
+ end
212
+ #TSV: tab separated value 読み込みメソッド
213
+ def makeMatrixFromTSV(file, opts={:sep=>SEPARATOR, :offset=>0})
214
+ out = []
215
+ epath = encodePath(file)
216
+ if(!File.exist?(epath))
217
+ open(epath, 'w') do |fo|
218
+ fo.print("\n\n")
219
+ end
220
+ end
221
+ #fi = open(file.encode('Windows-31J'), "r:Windows-31J")
222
+ fi = open(encodePath(file), "r:Windows-31J")
223
+ if(opts[:offset])
224
+ opts[:offset].times do |i|
225
+ fi.gets
226
+ end
227
+ end
228
+ opts[:sep]||=SEPARATOR
229
+ fi.each do |line|
230
+ row = MyMatrix.toutf8(line).chomp.split(/#{opts[:sep]}/)
231
+ #「1,300台」などカンマが使われている場合、「"1,300台"」となってしまうので、カンマを無視する
232
+ newRow = []
233
+ row.each do |cell|
234
+ stri = cell.dup
235
+ stri.gsub!(/^\"(.*)\"$/, '\1')
236
+ #"
237
+ stri.gsub!(/""/, '"')
238
+ newRow << stri
239
+ end
240
+ out << newRow
241
+ end
242
+ fi.close
243
+ return out
244
+ end
245
+
246
+ #CSV読み込みメソッド
247
+ def makeMatrixFromCSV(file, opts={:offset=>0})
248
+ #1.9系ではFasterCSVを使えない
249
+ if(RUBY_VERSION =~ /1\.[^9]/)
250
+ #1.8以下の場合
251
+ require 'fastercsv'
252
+ csv = FasterCSV
253
+ else
254
+ #1.9以上の場合
255
+ require 'csv'
256
+ Encoding.default_external = 'Windows-31J'
257
+ csv = CSV
258
+ end
259
+ out = []
260
+ i= 0
261
+ syspath = encodePath(file)
262
+ csv.foreach(syspath, {:row_sep => "\r\n", :encoding => 'Shift_JIS'}) do |row|
263
+ if(opts[:offset])
264
+ if(opts[:offset] < i)
265
+ next
266
+ end
267
+ end
268
+ #「1,300台」などカンマが使われている場合、「"1,300台"」となってしまうので、カンマを無視する
269
+ newRow = []
270
+ row.each do |cell|
271
+ cell = cell.to_s
272
+ cell ||= ''
273
+ cell = MyMatrix.toutf8(cell)
274
+ #cell = cell.gsub(/^\"/, "")
275
+ #cell = cell.gsub(/\"$/, "")
276
+ #"
277
+ newRow << cell
278
+ end
279
+ out << newRow
280
+ i += 1
281
+ end
282
+ return out
283
+ end
284
+
285
+ def isEnd(row)
286
+ out = true
287
+ row.each do |cell|
288
+ if(cell != "")
289
+ out = nil
290
+ break
291
+ end
292
+ end
293
+ return out
294
+ end
295
+
296
+ public
297
+ # カラムの値を配列で返却する
298
+ def getColumn(colName)
299
+ out = []
300
+ @mx.each do |row|
301
+ begin
302
+ out << getValue(row, colName)
303
+ rescue
304
+ raise "#{colName} notfound: #{row}"
305
+ end
306
+ end
307
+ return out
308
+ end
309
+
310
+ # getColumn のエイリアスメソッド
311
+ def getValues(colName)
312
+ return getColumn(colName)
313
+ end
314
+ #カラムの値を複数指定して、多次元配列を返却するメソッド。
315
+ def getColumns(colNames)
316
+ out = []
317
+ colNames.each do |colName|
318
+ out << getColumn(colName)
319
+ end
320
+ return out
321
+ end
322
+
323
+ #
324
+ def getColumnsByMatrix(colNames)
325
+ out = MyMatrix.new
326
+ colNames.each do |colName|
327
+ col = getColumn(colName)
328
+ out.addColumn(colName, col)
329
+ end
330
+ return out
331
+ end
332
+ def val(row, str)
333
+ getValue(row, str)
334
+ end
335
+
336
+ def getValue(row, str)
337
+ out = nil
338
+ index = @headerH[str]
339
+ if(index)
340
+ out = row[index]
341
+ #お尻のセルでNULLの場合などは、nilが返却されてしまう。なので、''となるようにする。
342
+ if(!out)
343
+ out = ''
344
+ end
345
+ #参照を渡さないためdupする
346
+ out = out.dup
347
+ else
348
+ raise "header not found:#{str} file:#{@file}"
349
+ end
350
+ return out
351
+ end
352
+ alias val getValue
353
+ =begin
354
+ def getValues(row, arr)
355
+ out = []
356
+ arr.each do |ele|
357
+ out << getValue(row, ele)
358
+ end
359
+ if(out.size == 0)
360
+ out = nil
361
+ end
362
+ return out
363
+ end
364
+ =end
365
+ def setValue(row, str, value)
366
+ if(!row)
367
+ raise 'row is nil'
368
+ end
369
+ index = @headerH[str]
370
+ if(!index)
371
+ addHeaders([str])
372
+ end
373
+ #参照先の値も変更できるように、破壊メソッドを使う。row[@headerH[str]] = valueでは、参照先が切り替わってしまうので、値の置き換えにならない。
374
+ #findなどで取得したrowに対して処理を行う際に必要な変更。
375
+ if(row[@headerH[str]].class == String)
376
+ row[@headerH[str]].sub!(/^.*$/, value)
377
+ else
378
+ #raise('not string error.')
379
+ #todo 強烈なバグな気もするが、例外を回避し値を代入2010年12月15日
380
+ begin
381
+ row[@headerH[str]] = value.to_s
382
+ rescue
383
+ row[@headerH[str]] = ''
384
+ end
385
+ end
386
+ end
387
+ def each
388
+ @mx.each do |row|
389
+ yield(row)
390
+ end
391
+ end
392
+ #未検証
393
+ def reverse
394
+ out = empty
395
+
396
+ @mx.reverse.each do |row|
397
+ out << row
398
+ end
399
+ return out
400
+ end
401
+
402
+
403
+ def size
404
+ return @mx.size
405
+ end
406
+ def [](i,j)
407
+ return @mx[i][j]
408
+ end
409
+
410
+ def [](i)
411
+ return @mx[i]
412
+ end
413
+
414
+ #未検証
415
+ def +(other)
416
+ out = MyipcMatrix.new
417
+
418
+ othHeaders = other.getHeaders
419
+ selHeaders = getHeaders
420
+
421
+ selHeaders.each do |header|
422
+ out.addColumn(header, getColumn(header))
423
+ end
424
+
425
+ othHeaders.each do |header|
426
+ out.addColumn(header, other.getColumn(header))
427
+ end
428
+
429
+ return out
430
+ end
431
+
432
+ def addColumn(header, column)
433
+ pushColumn(header, column)
434
+ end
435
+ def <<(row)
436
+ addRow(row)
437
+ end
438
+ def addRow(row)
439
+ if(row.class != Array)
440
+ row = [row]
441
+ end
442
+ row.size.times do |i|
443
+ if(row[i] == nil)
444
+ row[i] = ''
445
+ end
446
+ end
447
+
448
+ headerSize = getHeaders.size
449
+ rowSize = row.size
450
+ if(headerSize > rowSize)
451
+ (headerSize - rowSize).times do |i|
452
+ row << ''
453
+ end
454
+ elsif(rowSize > headerSize)
455
+ raise("row size error. headerSize:#{headerSize} rowSize:#{rowSize}")
456
+ end
457
+ @mx << row.dup
458
+ end
459
+ def [](i)
460
+ return @mx[i]
461
+ end
462
+ def []=(key, value)
463
+ @mx[key] = value
464
+ end
465
+
466
+ def pushColumn(header, column)
467
+ colPos = @headers.length
468
+ @headers << header
469
+ registerMatrix
470
+ column.each_with_index do |cell, i|
471
+ if(@mx[i] == nil)
472
+ @mx[i] = []
473
+ end
474
+ @mx[i][colPos] = cell
475
+ end
476
+ end
477
+ #使い勝手が良くないので気をつけて使う(todo参照)
478
+ def unShiftColumn(header, column)
479
+ @headers.unshift(header)
480
+ registerMatrix
481
+ column.each_with_index do |cell, i|
482
+ if(@mx[i] == nil)
483
+ @mx[i] = []
484
+ end
485
+ #todo:ヘッダよりでかいrowがある場合バグる。期待していない一番右の値が取れてしまう。
486
+ @mx[i].unshift(cell)
487
+ end
488
+ end
489
+
490
+ def shiftColumn()
491
+ header = @headers.shift
492
+ column = []
493
+ registerMatrix
494
+ @mx.each do |row|
495
+ column << row.shift
496
+ end
497
+ return header, column
498
+ end
499
+
500
+ #複数に分割されたテキストファイルを出力する
501
+ def divide(splitNum)
502
+ lineNum = (@mx.size / splitNum) + 1
503
+ mymxs = []
504
+ tmp = MyMatrix.new
505
+ tmp.file = @file
506
+ tmp.addHeaders(getHeaders)
507
+ @mx.each_with_index do |row, i|
508
+ tmp << row.dup
509
+ if((i+1) % lineNum == 0)
510
+ mymxs << tmp
511
+ tmp = MyMatrix.new
512
+ tmp.addHeaders(getHeaders)
513
+ tmp.file = @file
514
+ end
515
+ end
516
+ mymxs << tmp
517
+ mymxs.each_with_index do |mymx, i|
518
+ p i
519
+ mymx.to_t_with("#{i}")
520
+ end
521
+ end
522
+ #ファイルの中身をSJISにするために使ってる
523
+ def localEncode(v, enc = 's')
524
+ case enc
525
+ when 'u'
526
+ str = MyMatrix.toutf8(v)
527
+ when 's'
528
+ str = MyMatrix.tosjis(v)
529
+ else
530
+ str = MyMatrix.tosjis(v)
531
+ end
532
+ end
533
+ #使い方はto_t()を参照。yield。
534
+ def to_text(outFile)
535
+ outFile = encodePath(outFile)
536
+ out = []
537
+ out << @headers
538
+ @mx.each do |row|
539
+ out << row
540
+ end
541
+ begin
542
+ fo = open(outFile, 'wb')
543
+ rescue => e
544
+ p "cannot write file...#{outFile}"
545
+ p e
546
+ sleep(5)
547
+ retry
548
+ end
549
+ out.each_with_index do |row, i|
550
+ if(row == nil)
551
+ warn("line #{i} is nil")
552
+ fo.print("")
553
+ else
554
+ str = yield(row)
555
+ fo.print(str)
556
+ end
557
+ fo.print("\r\n")
558
+ end
559
+ fo.close
560
+ end
561
+ # テキスト出力する
562
+ def to_t(outFile=nil, opts={})
563
+ if(!outFile)
564
+ outFile = @file
565
+ end
566
+
567
+ #拡張子の判別
568
+ ext = File.extname(outFile).downcase
569
+ case ext
570
+ when '.csv'
571
+ opts[:separator] ||= ','
572
+ opts[:escape] ||= true
573
+ when '.xls'
574
+ p 'use Tab-Separated-Value text format.'
575
+ outFile = outFile + '.txt'
576
+ when '.xlsx'
577
+ p 'use Tab-Separated-Value text format.'
578
+ outFile = outFile + '.txt'
579
+ else
580
+ #do nothing
581
+ end
582
+ #デフォルトオプションの設定
583
+ opts[:enc] ||= 's'
584
+ opts[:escape] ||= false
585
+ opts[:separator] ||= SEPARATOR
586
+
587
+ to_text(outFile) do |row|
588
+ orow = []
589
+ if(opts[:escape])
590
+ row.each do |cell|
591
+ orow << myescape(cell)
592
+ end
593
+ else
594
+ row.each do |cell|
595
+ orow << cell.to_s.gsub(/[#{opts[:separator]}\r\n]/, '')
596
+ end
597
+ end
598
+
599
+ begin
600
+ str = localEncode(orow.join(opts[:separator]), opts[:enc])
601
+ rescue Encoding::UndefinedConversionError
602
+ orow.each do |ele|
603
+ begin
604
+ localEncode(ele, opts[:enc])
605
+ rescue
606
+ raise "encode error.#{ele}\n(#{orow})"
607
+ end
608
+ end
609
+
610
+ @log.debug(row.join(opts[:separator]))
611
+ end
612
+ str
613
+ end
614
+ end
615
+ def myescape(cell)
616
+ o = cell.to_s.dup
617
+ o.gsub!(/"/, '""')
618
+ if o =~ /[",']/
619
+ #'
620
+ o = "\"#{o}\""
621
+ end
622
+ return o
623
+ end
624
+ # 読み込んだファイル名にpostfixを付与してテキストファイル出力する
625
+ def to_t_with(postfix="out", opts={})
626
+ opath = MyMatrix.make_path(@file, {:ext=>nil, :postfix=>postfix})
627
+ to_t(opath, opts)
628
+ return opath
629
+ end
630
+
631
+ #CSV出力する。ダブルクオーテーションやカンマをエスケープする。
632
+ def to_csv(outFile)
633
+ to_t(outFile, {:separator=>',', :escape=>true})
634
+ end
635
+
636
+ #ヘッダのコピーを返却する
637
+ def getHeaders
638
+ out = @headers.dup
639
+ return out
640
+ end
641
+ #ヘッダを置き換える
642
+ def replaceHeader(before, after)
643
+ @headers[@headerH[before]] = after
644
+ registerMatrix
645
+ end
646
+
647
+ # colNameの値がvalueの行のうち先頭のものを返却する。todo:名称がよくない。
648
+ def index(colName, value)
649
+ out = nil
650
+ col = getColumn(colName)
651
+ col.each_with_index do |cell, i|
652
+ if(value == cell)
653
+ out = i
654
+ break
655
+ end
656
+ end
657
+ return out
658
+ end
659
+
660
+ # colnameの値がvalueの行のもののインデックス値を配列で返却する。todo:名称がよくない。
661
+ def searchIndexes(colName, value)
662
+ out = []
663
+ col = getColumn(colName)
664
+ col.each_with_index do |cell, i|
665
+ if(value == cell)
666
+ out << i
667
+ end
668
+ end
669
+ return out
670
+ end
671
+
672
+ # colnameの値がvalueの行のrowを配列で返却する。todo:名称がよくない。
673
+ def search(colName, value)
674
+ indexes = []
675
+ col = getColumn(colName)
676
+ col.each_with_index do |cell, i|
677
+ if(value == cell)
678
+ indexes << i
679
+ end
680
+ end
681
+ out = self.empty
682
+ indexes.each do |index|
683
+ out << @mx[index]
684
+ end
685
+ return out
686
+ end
687
+ # ヘッダを追加する(配列)
688
+ def addHeaders(aheaders)
689
+ @headers.concat(aheaders).uniq!
690
+
691
+ registerMatrix
692
+ end
693
+
694
+ # ヘッダを追加する
695
+ def addHeader(key)
696
+ addHeaders([key])
697
+ end
698
+
699
+ #行数を返却する
700
+ def size
701
+ return @mx.size
702
+ end
703
+
704
+ #未検証。「要素の重複判定は、Object#eql? により行われます。」http://www.ruby-lang.org/ja/old-man/html/Array.html#uniq
705
+ def uniq!
706
+ @mx.uniq!
707
+ end
708
+
709
+ def shift
710
+ return @mx.shift
711
+ end
712
+ def unshift(var)
713
+ return @mx.unshift(var)
714
+ end
715
+ def pop
716
+ return @mx.pop
717
+ end
718
+ def push(var)
719
+ return @mx.push(var)
720
+ end
721
+ def delete_at(pos)
722
+ @mx.delete_at(pos)
723
+ end
724
+
725
+ #未検証。「要素を順番にブロックに渡して評価し、その結果が真になった要素を すべて削除します。」
726
+ def delete_if
727
+ out = @mx.delete_if do |row|
728
+ yield(row)
729
+ end
730
+ @mx = out
731
+ end
732
+ def delete(v)
733
+ @mx.delete(v)
734
+ end
735
+ #ブロックがTrueになる、配列(参照)を返却するメソッド
736
+ def find
737
+ #todo rowsを返却するのと、Mymatrxixを返却するのとどっちがイイのか。。
738
+ rows = []
739
+ @mx.each do |row|
740
+ if(yield(row))
741
+ rows << row.dup
742
+ end
743
+ end
744
+ return rows
745
+ end
746
+
747
+ #headersに記載の
748
+ def select(headers)
749
+ out = self.class.new
750
+ headers.each do |header|
751
+ out.addColumn(header, getColumn(header))
752
+ end
753
+ out.file = @file
754
+ return out
755
+ end
756
+
757
+ #fromColName => toColNameのハッシュを作成する。
758
+ #fromColNameの値が同じだとtoColNameが上書きされるので使いにくいと思われる。
759
+ def makeHash(fromColName, toColName)
760
+ out = Hash.new
761
+ @mx.each do |row|
762
+ from = getValue(row, fromColName)
763
+ to = getValue(row, toColName)
764
+ out[from] = to
765
+ end
766
+ return out
767
+ end
768
+
769
+ #colnameがキーのハッシュを作る。valueはrowの配列。
770
+ def makeKey(colname)
771
+ out = {}
772
+ self.each do |row|
773
+ key = self.val(row, colname)
774
+ if(out[key] == nil)
775
+ out[key] = []
776
+ end
777
+ out[key] << row
778
+ end
779
+ return out
780
+ end
781
+
782
+ #MyipcMatrixとの互換性のため。getValueのエイリアス
783
+ def getCrrValue(row, str)
784
+ p 'this class is not MyipcMatrix.'
785
+ getValue(row, str)
786
+ end
787
+
788
+ def concatCells(headers, colname)
789
+ addHeaders([colname])
790
+ @mx.each do |row|
791
+ val = []
792
+ headers.each do |header|
793
+ val << getValue(row, header)
794
+ end
795
+ setValue(row, colname, val.join('_').gsub(/_+/, '_'))
796
+ end
797
+ end
798
+
799
+ #読み込んだファイルのパスを返却する
800
+ def getPath
801
+ return @file
802
+ end
803
+ #ファイルパスを設定する。 to_tを引数なしで使うと、設定したパスにファイルが生成される。
804
+ def setPath(path)
805
+ @file = path
806
+ end
807
+
808
+ # strを含む(/#{str}/)ヘッダ名を配列で返却する。
809
+ def searchHeader(str)
810
+ out = []
811
+ getHeaders.each do |header|
812
+ if(header =~ /#{str}/)
813
+ out << header
814
+ end
815
+ end
816
+ end
817
+
818
+ #n分割した配列を返却する
819
+ def devide(n)
820
+ out = []
821
+ mx = @mx.dup
822
+ eleSize = mx.size/n
823
+ n.times do |i|
824
+ o = self.empty
825
+ eleSize.times do |j|
826
+ o << mx.shift
827
+ end
828
+ out << o
829
+ end
830
+ #@mx.size%n分余ってるので、追加
831
+ mx.each do |ele|
832
+ out[n-1] << ele
833
+ end
834
+ return out
835
+ end
836
+ #compareHeaderの値の中に、valuesに書かれた値があったら、targetHeaderにフラグを立てる
837
+ def addFlg(targetHeader, compareHeader, values, flgValue='1')
838
+ compares = getColumn(compareHeader)
839
+ values.each do|value|
840
+ i = compares.index(value)
841
+ if(i)
842
+ setValue(@mx[i], targetHeader, flgValue)
843
+ else
844
+ #raise "VALUE NOT FOUND:#{value}"
845
+ end
846
+ end
847
+ end
848
+
849
+ def without(regexp_or_string)
850
+ if(regexp_or_string.class == String)
851
+ regexp = /#{regexp_or_string}/
852
+ else
853
+ regexp = regexp_or_string
854
+ end
855
+ newHeaders = []
856
+ @headers.each do |header|
857
+ if(header =~ regexp)
858
+ else
859
+ newHeaders << header
860
+ end
861
+ end
862
+ out = select(newHeaders)
863
+ return out
864
+ end
865
+
866
+ #行が空(ヘッダはそのまま)のコピーを返却する
867
+ def empty
868
+ out = self.dup
869
+ out.empty!
870
+ return out
871
+ end
872
+
873
+ #selfの行を空にする
874
+ def empty!
875
+ @mx = []
876
+ return self
877
+ end
878
+ def fill(rows)
879
+ rows.each do |row|
880
+ self << row
881
+ end
882
+ return self
883
+ end
884
+
885
+ #行番号を付与する
886
+ def with_serial(headerName = 'No.')
887
+ out = self.empty
888
+ out.addHeaders([headerName], 1)
889
+ self.each_with_index do |row, i|
890
+ no = i + 1
891
+ newRow = [no].concat(row)
892
+ out << newRow
893
+ end
894
+ return out
895
+ end
896
+
897
+
898
+ def count(header, value)
899
+ out = 0
900
+ arr = getColumn(header)
901
+ arr.each do |ele|
902
+ if(ele =~ /#{value}/)
903
+ out += 1
904
+ end
905
+ end
906
+ return out
907
+ end
908
+ #全件カウントして、[value, count] という配列に格納する
909
+ def countup(header)
910
+ out = []
911
+ values = getColumn(header).uniq
912
+ values.each do |value|
913
+ out << [value, self.count(header, value)]
914
+ end
915
+ return out
916
+ end
917
+ def getDoubles(arr)
918
+ doubles = arr.select do |e|
919
+ arr.index(e) != arr.rindex(e)
920
+ end
921
+ doubles.uniq!
922
+ return doubles
923
+ end
924
+
925
+ def filter(header, value)
926
+ out = empty
927
+ @mx.each do|row|
928
+ v = getValue(row, header)
929
+ if(v == value)
930
+ out << row
931
+ end
932
+ end
933
+ return out
934
+ end
935
+ #配列と引き算とかする際に使われる。
936
+ def to_ary
937
+ arr = []
938
+ @mx.each do |row|
939
+ #arr << row.dup
940
+ arr << row
941
+ end
942
+ return arr
943
+ end
944
+ def to_s
945
+ out = ''
946
+ @mx.each do |row|
947
+ out = out + row.to_s + "\n"
948
+ end
949
+ return out
950
+ end
951
+ def to_s_with_header
952
+ out = self.getHeaders.to_s + "\n"
953
+ out = out + self.to_s
954
+ end
955
+ def concat(mx, opt={})
956
+ notfoundHeaders = []
957
+ mx.each do |row|
958
+ o = []
959
+ mx.getHeaders.each do |head|
960
+ begin
961
+ self.setValue(o, head, mx.getValue(row, head))
962
+ rescue => e
963
+ #p e
964
+ if(opt[:loose]==true)
965
+ self.addHeaders([head])
966
+ #p "#{head} added"
967
+ retry
968
+ else
969
+ notfoundHeaders << head
970
+ end
971
+ end
972
+ end
973
+ self << o
974
+ end
975
+ if(notfoundHeaders.size > 0)
976
+ raise "notfoundHeader : #{notfoundHeaders.uniq.join(',')}"
977
+ end
978
+ return self
979
+ end
980
+ def concatFile(file, opt={})
981
+ #p file
982
+ mx = MyMatrix.new(file)
983
+ self.concat(mx, opt)
984
+ return self
985
+ end
986
+ #フォルダ内ファイルの結合。絶対パスを指定する
987
+ def concatDir(dir)
988
+ dir = File.expand_path(dir)
989
+ Dir.entries(dir).each do |ent|
990
+ if(ent =~ /^\./)
991
+ else
992
+ #p ent
993
+
994
+ file = dir + '/' + ent
995
+ #p "concat:#{file}"
996
+ nmx = MyMatrix.new(file)
997
+ self.concat(nmx)
998
+ end
999
+ end
1000
+
1001
+ end
1002
+ =begin
1003
+ def concat!(mx)
1004
+ o = self.concat(mx)
1005
+ self = o
1006
+ return self
1007
+ end
1008
+ def concatFile!(file)
1009
+ o = self.concatFile(file)
1010
+ self = o
1011
+ return self
1012
+ end
1013
+ =end
1014
+ def flushCol(colname)
1015
+ @mx.each do |row|
1016
+ self.setValue(row, colname, '')
1017
+ end
1018
+ return self
1019
+ end
1020
+ def sortBy(colname, reverse=false)
1021
+ sortmx = []
1022
+ self.each do |row|
1023
+ key = self.getValue(row, colname)
1024
+ sortmx << [key, row]
1025
+ end
1026
+ sortmx.sort!
1027
+ self.empty!
1028
+ sortmx.each do |keyrow|
1029
+ self << keyrow[1]
1030
+ end
1031
+ return self
1032
+ end
1033
+ def dupRow(row, destmx, destrow, headers)
1034
+ headers.each do |head|
1035
+ val = self.getValue(row, head)
1036
+ destmx.setValue(destrow, head, val)
1037
+ end
1038
+ return destrow
1039
+ end
1040
+ def setSame(head, headValue, hash)
1041
+ idxs = self.searchIndexes(head, headValue)
1042
+ idxs.each do |idx|
1043
+ hash.each_pair do |key, value|
1044
+ self.setValue(@mx[idx], key, value)
1045
+ end
1046
+ end
1047
+ end
1048
+
1049
+ #都道府県市区町村コードの桁そろえ
1050
+ #Excelで先頭の0が落ちて桁が変わるため
1051
+ def correctCityCodes!(colname = '都道府県市区町村コード')
1052
+ self.each do |row|
1053
+ code = self.val(row, colname)
1054
+ if(code.length == 4)
1055
+ self.setValue(row, colname, sprintf("%05d", code))
1056
+ elsif(code.length == 5)
1057
+ #correct
1058
+ else
1059
+ raise "Citycode length error. '#{code}'"
1060
+ end
1061
+ end
1062
+ return self
1063
+ end
1064
+
1065
+ #末尾空白の削除
1066
+ def delEndSp!
1067
+ self.each do |row|
1068
+ self.getHeaders.each do |head|
1069
+ val = self.val(row, head)
1070
+ if(val =~ /(.*)[  ]$/)
1071
+ self.setValue(row, head, $1)
1072
+ end
1073
+ end
1074
+ end
1075
+ return self
1076
+ end
1077
+ #半角カタカナの全角化
1078
+ def twoByteKana!
1079
+ self.each do |row|
1080
+ self.getHeaders.each do |head|
1081
+ val = self.val(row, head)
1082
+ #if(val =~ /[-~]/)
1083
+ if(val =~ /[-]/)
1084
+ #p "#{self.file} #{val}"
1085
+ next
1086
+ end
1087
+ #nval = Kconv.kconv(val, Kconv::UTF8, Kconv::UTF8)
1088
+ #nval = NKF.nkf('-W -w -x --cp932', val)
1089
+
1090
+ nval = NKF.nkf('-W -w', val)
1091
+
1092
+ if(val!=nval)
1093
+ #p "#{val}=>#{nval}"
1094
+ end
1095
+ self.setValue(row, head, nval)
1096
+ end
1097
+ end
1098
+ return self
1099
+ end
1100
+ #CP932範囲外の文字コードを変換する関数。ruby1.9の正規表現(鬼車)のため、1.8では使えない。
1101
+ def self.cp932ize(str)
1102
+ out = str.dup
1103
+ cases = [
1104
+ #['−', '―'], #MINUS SIGN(U+2212) to FULLWIDTH HYPHEN-MINUS(U+2015)(windows)
1105
+ #↑仕様としては上記が正しいが、運用上MINUS SIGN(U+2212) は FULLWIDTH HYPHEN-MINUS(U+FF0D)に変換する
1106
+ #キー入力時にMacとWindowsで同じ文字コードとなることが望ましいため。
1107
+
1108
+ ['',''], #WAVE DASH (U+301C) to FULLWIDTH TILDE(U+FF5E)(windows)
1109
+ ['‖','∥'], #DOUBLE VERTICAL LINE (U+2016, "‖") を PARALLEL TO (U+2225, "∥") に
1110
+ ['', ''], #EM DASH (U+2014, "—") を HORIZONTAL BAR (U+2015, "―")
1111
+ #以下、キー入力を想定した変換。
1112
+ ['', ''], #MacのハイフンF7(google ime)→Windows(googleime):同じ
1113
+ ['', ''], #MacのハイフンF8(google ime)→Windows(googleime):同じ
1114
+ ['−', '-'], #MacのハイフンF9[−](google ime)→Windows[-](googleime):違う。MINUS SIGN(U+2212) to FULLWIDTH HYPHEN-MINUS(U+FF0D)
1115
+ ['-', '-'], #MacのハイフンF10(google ime)→Windows(googleime):同じ
1116
+ #ユニコード固有文字:ノーブレークスペース
1117
+ ['[\u00A0]', ' '],
1118
+ #yen
1119
+ ['[\u00A5]', ''],
1120
+ # éとè:eの上に´と`
1121
+ ['[\u00E9]', 'e'],['[\u00E8]', 'e'],
1122
+ #spaces
1123
+ ['[\u2000]', ' '],['[\u2001]', ' '],['[\u2002]', ' '],['[\u2003]', ' '],['[\u2004]', ' '],['[\u2005]', ' '],['[\u2006]', ' '],['[\u2007]', ' '],['[\u2008]', ' '],['[\u2009]', ' '],['[\u200A]', ' '],['[\u205F]', ' ']
1124
+ ]
1125
+ cases.each do |c|
1126
+ out.gsub!(/#{c[0]}/, c[1])
1127
+ end
1128
+ return out
1129
+ end
1130
+ # def save(file)
1131
+ # p Marshal.dump(self)
1132
+ # open(file, 'w') do |fo|
1133
+ # fo.write(Marshal.dump(self))
1134
+ # end
1135
+ # end
1136
+
1137
+ =begin
1138
+ def to_xls(opts)
1139
+ if(opts[:out] =~ /.xls$/)
1140
+ else
1141
+ raise "not outfile"
1142
+ end
1143
+ opts[:template] ||= opts[:out]
1144
+
1145
+ opts[:offset_r] ||= 0
1146
+ opts[:offset_c] ||= 0
1147
+
1148
+ xl = Spreadsheet.open(encodePath(opts[:template]), 'r')
1149
+ sheet = xl.worksheet(0)
1150
+ @headers.each_with_index do |head, i|
1151
+ ab_row = opts[:offset_r]
1152
+ ab_col = opts[:offset_c] + i
1153
+ sheet[ab_row, ab_col] = head
1154
+ end
1155
+ self.each_with_index do |row, i|
1156
+ row.each_with_index do |cell, j|
1157
+ ab_row = opts[:offset_r] + i + 1
1158
+ #↑ヘッダ分1オフセット
1159
+ ab_col = opts[:offset_c] + j
1160
+ sheet[ab_row, ab_col] = cell
1161
+ end
1162
+ end
1163
+
1164
+ xl.write(opts[:out])
1165
+
1166
+ end
1167
+ =end
1168
+ #Arrayっぽく使うためのメソッド。内部の@mx.first
1169
+ def first
1170
+ @mx[0]
1171
+ end
1172
+ #Arrayっぽく使うためのメソッド。内部の@mx.last
1173
+ def last
1174
+ out = @mx[self.size-1]
1175
+ end
1176
+ def empty?
1177
+ @mx.empty?
1178
+ end
1179
+ #num文字以上の項目をnum文字に丸める
1180
+ def cutOff(head, num)
1181
+ self.each do |row|
1182
+ v = self.val(row, head)
1183
+ if(v =~ /(.{#{num}})/)
1184
+ self.setValue(row, head, $1)
1185
+ end
1186
+ end
1187
+ end
1188
+ def self.make_path(path, opts={ })
1189
+ # opath = makepath(@file, {:ext=>nil, :postfix=>postfix})
1190
+ dir = File.dirname(path)
1191
+ ext = opts[:ext]
1192
+ ext ||= File.extname(path)
1193
+ postfix = opts[:postfix].to_s
1194
+
1195
+ basename = File.basename(path, ".*")
1196
+ opath = (MyMatrix.new.encodePath("#{dir}/#{basename}_#{postfix}#{ext}"))
1197
+ end
1198
+ end
1199
+
1200
+ #ruby -Ks で利用する場合。ruby1.9では使えないはず。obsolete
1201
+ class SjisMyMatrix < MyMatrix
1202
+ def getValue(row, col)
1203
+ col = MyMatrix.toutf8(col)
1204
+ MyMatrix.tosjis(super(row, col))
1205
+ end
1206
+ def setValue(row, col, value)
1207
+ col = MyMatrix.toutf8(col)
1208
+ value = MyMatrix.toutf8(value)
1209
+ super(row, col, value)
1210
+ end
1211
+ def addHeaders(hs)
1212
+ arr =[]
1213
+ hs.each do |ele|
1214
+ arr << MyMatrix.toutf8(ele)
1215
+ end
1216
+ super(arr)
1217
+ end
1218
+ def getHeaders
1219
+ out = []
1220
+ arr = super()
1221
+ arr.each do |ele|
1222
+ out << MyMatrix.tosjis(ele)
1223
+ end
1224
+ return out
1225
+ end
1226
+ end
1227
+
1228
+
1229
+ #rails で使う場合。obsolete
1230
+ class MyRailsMatrix < MyMatrix
1231
+ def headers2db(t)
1232
+ getHeaders.each do |header|
1233
+ t.column header, :string
1234
+ end
1235
+ end
1236
+ end
1237
+
1238
+