writeexcel 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +26 -31
- data/examples/a_simple.rb +42 -42
- data/examples/{autofilters.rb → autofilter.rb} +264 -266
- data/examples/bigfile.rb +29 -0
- data/examples/chart_area.rb +120 -0
- data/examples/chart_bar.rb +119 -0
- data/examples/chart_column.rb +119 -0
- data/examples/chart_line.rb +119 -0
- data/examples/chart_pie.rb +107 -0
- data/examples/chart_scatter.rb +120 -0
- data/examples/chart_stock.rb +147 -0
- data/examples/copyformat.rb +51 -51
- data/examples/data_validate.rb +278 -278
- data/examples/date_time.rb +86 -86
- data/examples/defined_name.rb +31 -0
- data/examples/demo.rb +120 -118
- data/examples/diag_border.rb +35 -35
- data/examples/formats.rb +489 -489
- data/examples/header.rb +136 -136
- data/examples/hidden.rb +28 -28
- data/examples/hyperlink.rb +42 -42
- data/examples/images.rb +52 -52
- data/examples/merge1.rb +39 -39
- data/examples/merge2.rb +44 -44
- data/examples/merge3.rb +65 -65
- data/examples/merge4.rb +82 -82
- data/examples/merge5.rb +79 -79
- data/examples/properties.rb +33 -0
- data/examples/properties_jp.rb +32 -0
- data/examples/protection.rb +46 -46
- data/examples/regions.rb +52 -52
- data/examples/repeat.rb +42 -42
- data/examples/stats.rb +75 -75
- data/examples/stocks.rb +80 -80
- data/examples/tab_colors.rb +30 -30
- data/examples/write_arrays.rb +82 -0
- data/lib/writeexcel.rb +1134 -18
- data/lib/writeexcel/biffwriter.rb +273 -260
- data/lib/writeexcel/chart.rb +2306 -217
- data/lib/writeexcel/charts/area.rb +152 -0
- data/lib/writeexcel/charts/bar.rb +177 -0
- data/lib/writeexcel/charts/column.rb +156 -0
- data/lib/writeexcel/charts/external.rb +61 -0
- data/lib/writeexcel/charts/line.rb +152 -0
- data/lib/writeexcel/charts/pie.rb +169 -0
- data/lib/writeexcel/charts/scatter.rb +192 -0
- data/lib/writeexcel/charts/stock.rb +211 -0
- data/lib/writeexcel/excelformulaparser.rb +208 -195
- data/lib/writeexcel/format.rb +1697 -1108
- data/lib/writeexcel/formula.rb +1050 -986
- data/lib/writeexcel/olewriter.rb +322 -322
- data/lib/writeexcel/properties.rb +251 -250
- data/lib/writeexcel/storage_lite.rb +968 -0
- data/lib/writeexcel/workbook.rb +3294 -2630
- data/lib/writeexcel/worksheet.rb +9012 -6377
- data/test/excelfile/Chart1.xls +0 -0
- data/test/excelfile/Chart2.xls +0 -0
- data/test/excelfile/Chart3.xls +0 -0
- data/test/excelfile/Chart4.xls +0 -0
- data/test/excelfile/Chart5.xls +0 -0
- data/test/perl_output/Chart1.xls.data +0 -0
- data/test/perl_output/Chart2.xls.data +0 -0
- data/test/perl_output/Chart3.xls.data +0 -0
- data/test/perl_output/Chart4.xls.data +0 -0
- data/test/perl_output/Chart5.xls.data +0 -0
- data/test/perl_output/a_simple.xls +0 -0
- data/test/perl_output/autofilter.xls +0 -0
- data/test/perl_output/chart_area.xls +0 -0
- data/test/perl_output/chart_bar.xls +0 -0
- data/test/perl_output/chart_column.xls +0 -0
- data/test/perl_output/chart_line.xls +0 -0
- data/test/perl_output/data_validate.xls +0 -0
- data/test/perl_output/date_time.xls +0 -0
- data/test/perl_output/demo.xls +0 -0
- data/test/perl_output/demo101.bin +0 -0
- data/test/perl_output/demo201.bin +0 -0
- data/test/perl_output/demo301.bin +0 -0
- data/test/perl_output/demo401.bin +0 -0
- data/test/perl_output/demo501.bin +0 -0
- data/test/perl_output/diag_border.xls +0 -0
- data/test/perl_output/headers.xls +0 -0
- data/test/perl_output/hyperlink.xls +0 -0
- data/test/perl_output/images.xls +0 -0
- data/test/perl_output/merge1.xls +0 -0
- data/test/perl_output/merge2.xls +0 -0
- data/test/perl_output/merge3.xls +0 -0
- data/test/perl_output/merge4.xls +0 -0
- data/test/perl_output/merge5.xls +0 -0
- data/test/perl_output/protection.xls +0 -0
- data/test/perl_output/regions.xls +0 -0
- data/test/perl_output/stats.xls +0 -0
- data/test/perl_output/stocks.xls +0 -0
- data/test/perl_output/tab_colors.xls +0 -0
- data/test/perl_output/unicode_cyrillic.xls +0 -0
- data/test/perl_output/workbook1.xls +0 -0
- data/test/perl_output/workbook2.xls +0 -0
- data/test/tc_all.rb +32 -31
- data/test/tc_biff.rb +104 -104
- data/test/tc_chart.rb +22 -22
- data/test/tc_example_match.rb +1944 -1280
- data/test/tc_format.rb +1254 -1267
- data/test/tc_formula.rb +63 -63
- data/test/tc_ole.rb +110 -110
- data/test/tc_storage_lite.rb +149 -0
- data/test/tc_workbook.rb +140 -115
- data/test/tc_worksheet.rb +115 -115
- data/test/test_00_IEEE_double.rb +14 -14
- data/test/test_01_add_worksheet.rb +12 -12
- data/test/test_02_merge_formats.rb +58 -58
- data/test/test_04_dimensions.rb +397 -397
- data/test/test_05_rows.rb +182 -182
- data/test/test_06_extsst.rb +80 -80
- data/test/test_11_date_time.rb +484 -484
- data/test/test_12_date_only.rb +506 -506
- data/test/test_13_date_seconds.rb +486 -486
- data/test/test_21_escher.rb +642 -629
- data/test/test_22_mso_drawing_group.rb +750 -739
- data/test/test_23_note.rb +78 -78
- data/test/test_24_txo.rb +80 -80
- data/test/test_25_position_object.rb +82 -0
- data/test/test_26_autofilter.rb +327 -327
- data/test/test_27_autofilter.rb +144 -144
- data/test/test_28_autofilter.rb +174 -174
- data/test/test_29_process_jpg.rb +681 -131
- data/test/test_30_validation_dval.rb +82 -82
- data/test/test_31_validation_dv_strings.rb +131 -131
- data/test/test_32_validation_dv_formula.rb +211 -211
- data/test/test_40_property_types.rb +191 -191
- data/test/test_41_properties.rb +238 -238
- data/test/test_42_set_properties.rb +442 -419
- data/test/test_50_name_stored.rb +305 -0
- data/test/test_51_name_print_area.rb +363 -0
- data/test/test_52_name_print_titles.rb +460 -0
- data/test/test_53_autofilter.rb +209 -0
- data/test/test_60_chart_generic.rb +576 -0
- data/test/test_61_chart_subclasses.rb +97 -0
- data/test/test_62_chart_formats.rb +270 -0
- data/test/test_63_chart_area_formats.rb +647 -0
- data/test/test_chartex.rb +35 -0
- data/test/ts_all.rb +46 -34
- data/writeexcel.gemspec +18 -0
- data/writeexcel.rdoc +583 -0
- metadata +162 -108
data/lib/writeexcel/formula.rb
CHANGED
@@ -1,986 +1,1050 @@
|
|
1
|
-
###############################################################################
|
2
|
-
#
|
3
|
-
# Formula - A class for generating Excel formulas.
|
4
|
-
#
|
5
|
-
#
|
6
|
-
# Used in conjunction with
|
7
|
-
#
|
8
|
-
# Copyright 2000-
|
9
|
-
#
|
10
|
-
# original written in Perl by John McNamara
|
11
|
-
# converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
|
12
|
-
#
|
13
|
-
require 'nkf'
|
14
|
-
require 'strscan'
|
15
|
-
require 'writeexcel/excelformulaparser'
|
16
|
-
|
17
|
-
class Formula < ExcelFormulaParser
|
18
|
-
|
19
|
-
NonAscii = /[^!"#\$%&'\(\)\*\+,\-\.\/\:\;<=>\?@0-9A-Za-z_\[\\\]^` ~\0\n]/
|
20
|
-
|
21
|
-
attr_accessor :byte_order, :workbook, :ext_sheets, :ext_refs, :ext_ref_count
|
22
|
-
|
23
|
-
def initialize(byte_order)
|
24
|
-
@byte_order = byte_order
|
25
|
-
@workbook = ""
|
26
|
-
@ext_sheets = {}
|
27
|
-
@ext_refs = {}
|
28
|
-
@ext_ref_count = 0
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
#
|
45
|
-
#
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
#
|
52
|
-
#
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
elsif (token == '
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
_class = 1
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
_class = 1
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
_class = 1
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
_class = 1
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
q.push [:
|
164
|
-
elsif s.scan(/
|
165
|
-
q.push [:
|
166
|
-
elsif s.scan(
|
167
|
-
q.push [:
|
168
|
-
elsif s.scan(
|
169
|
-
q.push [:
|
170
|
-
elsif s.scan(
|
171
|
-
q.push [:
|
172
|
-
elsif s.scan(
|
173
|
-
q.push [:
|
174
|
-
elsif s.scan(
|
175
|
-
q.push [:
|
176
|
-
elsif s.scan(
|
177
|
-
q.push [:
|
178
|
-
elsif s.scan(
|
179
|
-
q.push [:
|
180
|
-
elsif s.scan(
|
181
|
-
q.push [:
|
182
|
-
elsif s.scan(
|
183
|
-
q.push [:
|
184
|
-
elsif s.scan(
|
185
|
-
|
186
|
-
elsif s.scan(
|
187
|
-
q.push [
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
end
|
262
|
-
|
263
|
-
###############################################################################
|
264
|
-
#
|
265
|
-
#
|
266
|
-
#
|
267
|
-
# Convert
|
268
|
-
#
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
#
|
277
|
-
#
|
278
|
-
#
|
279
|
-
#
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
#
|
523
|
-
#
|
524
|
-
#
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
#
|
535
|
-
#
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
if (
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
#
|
562
|
-
#
|
563
|
-
#
|
564
|
-
#
|
565
|
-
#
|
566
|
-
def
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
'
|
687
|
-
'
|
688
|
-
'
|
689
|
-
'
|
690
|
-
'
|
691
|
-
'
|
692
|
-
'
|
693
|
-
'
|
694
|
-
'
|
695
|
-
'
|
696
|
-
'
|
697
|
-
'
|
698
|
-
'
|
699
|
-
'
|
700
|
-
'
|
701
|
-
'
|
702
|
-
'
|
703
|
-
'
|
704
|
-
'
|
705
|
-
'
|
706
|
-
'
|
707
|
-
'
|
708
|
-
'
|
709
|
-
'
|
710
|
-
'
|
711
|
-
'
|
712
|
-
'
|
713
|
-
'
|
714
|
-
'
|
715
|
-
'
|
716
|
-
'
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
'
|
735
|
-
'
|
736
|
-
'
|
737
|
-
'
|
738
|
-
'
|
739
|
-
'
|
740
|
-
'
|
741
|
-
'
|
742
|
-
'
|
743
|
-
'
|
744
|
-
'
|
745
|
-
'
|
746
|
-
'
|
747
|
-
'
|
748
|
-
'
|
749
|
-
'
|
750
|
-
'
|
751
|
-
'
|
752
|
-
'
|
753
|
-
'
|
754
|
-
'
|
755
|
-
'
|
756
|
-
'
|
757
|
-
'
|
758
|
-
'
|
759
|
-
'
|
760
|
-
'
|
761
|
-
'
|
762
|
-
'
|
763
|
-
'
|
764
|
-
'
|
765
|
-
'
|
766
|
-
'
|
767
|
-
'
|
768
|
-
'
|
769
|
-
'
|
770
|
-
'
|
771
|
-
'
|
772
|
-
'
|
773
|
-
'
|
774
|
-
'
|
775
|
-
'
|
776
|
-
'
|
777
|
-
'
|
778
|
-
'
|
779
|
-
'
|
780
|
-
'
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
'
|
799
|
-
'
|
800
|
-
'
|
801
|
-
'
|
802
|
-
'
|
803
|
-
'
|
804
|
-
'
|
805
|
-
'
|
806
|
-
'
|
807
|
-
'
|
808
|
-
'
|
809
|
-
'
|
810
|
-
'
|
811
|
-
'
|
812
|
-
'
|
813
|
-
'
|
814
|
-
'
|
815
|
-
'
|
816
|
-
'
|
817
|
-
'
|
818
|
-
'
|
819
|
-
'
|
820
|
-
'
|
821
|
-
'
|
822
|
-
'
|
823
|
-
'
|
824
|
-
'
|
825
|
-
'
|
826
|
-
'
|
827
|
-
'
|
828
|
-
'
|
829
|
-
'
|
830
|
-
'
|
831
|
-
'
|
832
|
-
'
|
833
|
-
'
|
834
|
-
'
|
835
|
-
'
|
836
|
-
'
|
837
|
-
'
|
838
|
-
'
|
839
|
-
'
|
840
|
-
'
|
841
|
-
'
|
842
|
-
'
|
843
|
-
'
|
844
|
-
'
|
845
|
-
'
|
846
|
-
'
|
847
|
-
'
|
848
|
-
'
|
849
|
-
'
|
850
|
-
'
|
851
|
-
'
|
852
|
-
'
|
853
|
-
'
|
854
|
-
'
|
855
|
-
'
|
856
|
-
'
|
857
|
-
'
|
858
|
-
'
|
859
|
-
'
|
860
|
-
'
|
861
|
-
'
|
862
|
-
'
|
863
|
-
'
|
864
|
-
'
|
865
|
-
'
|
866
|
-
'
|
867
|
-
'
|
868
|
-
'
|
869
|
-
'
|
870
|
-
'
|
871
|
-
'
|
872
|
-
'
|
873
|
-
'
|
874
|
-
'
|
875
|
-
'
|
876
|
-
'
|
877
|
-
'
|
878
|
-
'
|
879
|
-
'
|
880
|
-
'
|
881
|
-
'
|
882
|
-
'
|
883
|
-
'
|
884
|
-
'
|
885
|
-
'
|
886
|
-
'
|
887
|
-
'
|
888
|
-
'
|
889
|
-
'
|
890
|
-
'
|
891
|
-
'
|
892
|
-
'
|
893
|
-
'
|
894
|
-
'
|
895
|
-
'
|
896
|
-
'
|
897
|
-
'
|
898
|
-
'
|
899
|
-
'
|
900
|
-
'
|
901
|
-
'
|
902
|
-
'
|
903
|
-
'
|
904
|
-
'
|
905
|
-
'
|
906
|
-
'
|
907
|
-
'
|
908
|
-
'
|
909
|
-
'
|
910
|
-
'
|
911
|
-
'
|
912
|
-
'
|
913
|
-
'
|
914
|
-
'
|
915
|
-
'
|
916
|
-
'
|
917
|
-
'
|
918
|
-
'
|
919
|
-
'
|
920
|
-
'
|
921
|
-
'
|
922
|
-
'
|
923
|
-
'
|
924
|
-
'
|
925
|
-
'
|
926
|
-
'
|
927
|
-
'
|
928
|
-
'
|
929
|
-
'
|
930
|
-
'
|
931
|
-
'
|
932
|
-
'
|
933
|
-
'
|
934
|
-
'
|
935
|
-
'
|
936
|
-
'
|
937
|
-
'
|
938
|
-
'
|
939
|
-
'
|
940
|
-
'
|
941
|
-
'
|
942
|
-
'
|
943
|
-
'
|
944
|
-
'
|
945
|
-
'
|
946
|
-
'
|
947
|
-
'
|
948
|
-
'
|
949
|
-
'
|
950
|
-
'
|
951
|
-
'
|
952
|
-
'
|
953
|
-
'
|
954
|
-
'
|
955
|
-
'
|
956
|
-
'
|
957
|
-
'
|
958
|
-
'
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
1
|
+
###############################################################################
|
2
|
+
#
|
3
|
+
# Formula - A class for generating Excel formulas.
|
4
|
+
#
|
5
|
+
#
|
6
|
+
# Used in conjunction with WriteExcel
|
7
|
+
#
|
8
|
+
# Copyright 2000-2010, John McNamara, jmcnamara@cpan.org
|
9
|
+
#
|
10
|
+
# original written in Perl by John McNamara
|
11
|
+
# converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
|
12
|
+
#
|
13
|
+
require 'nkf'
|
14
|
+
require 'strscan'
|
15
|
+
require 'writeexcel/excelformulaparser'
|
16
|
+
|
17
|
+
class Formula < ExcelFormulaParser #:nodoc:
|
18
|
+
|
19
|
+
NonAscii = /[^!"#\$%&'\(\)\*\+,\-\.\/\:\;<=>\?@0-9A-Za-z_\[\\\]^` ~\0\n]/
|
20
|
+
|
21
|
+
attr_accessor :byte_order, :workbook, :ext_sheets, :ext_refs, :ext_ref_count
|
22
|
+
|
23
|
+
def initialize(byte_order)
|
24
|
+
@byte_order = byte_order
|
25
|
+
@workbook = ""
|
26
|
+
@ext_sheets = {}
|
27
|
+
@ext_refs = {}
|
28
|
+
@ext_ref_count = 0
|
29
|
+
@ext_names = {}
|
30
|
+
initialize_hashes
|
31
|
+
end
|
32
|
+
|
33
|
+
###############################################################################
|
34
|
+
#
|
35
|
+
# parse_formula()
|
36
|
+
#
|
37
|
+
# Takes a textual description of a formula and returns a RPN encoded byte
|
38
|
+
# string.
|
39
|
+
#
|
40
|
+
def parse_formula(formula, byte_stream = false)
|
41
|
+
# Build the parse tree for the formula
|
42
|
+
tokens = reverse(parse(formula))
|
43
|
+
|
44
|
+
# Add a volatile token if the formula contains a volatile function.
|
45
|
+
# This must be the first token in the list
|
46
|
+
#
|
47
|
+
tokens.unshift('_vol') if check_volatile(tokens) != 0
|
48
|
+
|
49
|
+
# The return value depends on which Worksheet.pm method is the caller
|
50
|
+
unless byte_stream
|
51
|
+
# Parse formula to see if it throws any errors and then
|
52
|
+
# return raw tokens to Worksheet::store_formula()
|
53
|
+
#
|
54
|
+
parse_tokens(tokens)
|
55
|
+
tokens
|
56
|
+
else
|
57
|
+
# Return byte stream to Worksheet::write_formula()
|
58
|
+
parse_tokens(tokens)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
###############################################################################
|
63
|
+
#
|
64
|
+
# parse_tokens()
|
65
|
+
#
|
66
|
+
# Convert each token or token pair to its Excel 'ptg' equivalent.
|
67
|
+
#
|
68
|
+
def parse_tokens(tokens)
|
69
|
+
parse_str = ''
|
70
|
+
last_type = ''
|
71
|
+
modifier = ''
|
72
|
+
num_args = 0
|
73
|
+
_class = 0
|
74
|
+
_classary = [1]
|
75
|
+
args = tokens.dup
|
76
|
+
# A note about the class modifiers used below. In general the class,
|
77
|
+
# "reference" or "value", of a function is applied to all of its operands.
|
78
|
+
# However, in certain circumstances the operands can have mixed classes,
|
79
|
+
# e.g. =VLOOKUP with external references. These will eventually be dealt
|
80
|
+
# with by the parser. However, as a workaround the class type of a token
|
81
|
+
# can be changed via the repeat_formula interface. Thus, a _ref2d token can
|
82
|
+
# be changed by the user to _ref2dA or _ref2dR to change its token class.
|
83
|
+
#
|
84
|
+
while (!args.empty?)
|
85
|
+
token = args.shift
|
86
|
+
|
87
|
+
if (token == '_arg')
|
88
|
+
num_args = args.shift
|
89
|
+
elsif (token == '_class')
|
90
|
+
token = args.shift
|
91
|
+
_class = @functions[token][2]
|
92
|
+
# If _class is undef then it means that the function isn't valid.
|
93
|
+
exit "Unknown function #{token}() in formula\n" if _class.nil?
|
94
|
+
_classary.push(_class)
|
95
|
+
elsif (token == '_vol')
|
96
|
+
parse_str = parse_str + convert_volatile()
|
97
|
+
elsif (token == 'ptgBool')
|
98
|
+
token = args.shift
|
99
|
+
parse_str = parse_str + convert_bool(token)
|
100
|
+
elsif (token == '_num')
|
101
|
+
token = args.shift
|
102
|
+
parse_str = parse_str + convert_number(token)
|
103
|
+
elsif (token == '_str')
|
104
|
+
token = args.shift
|
105
|
+
parse_str = parse_str + convert_string(token)
|
106
|
+
elsif (token =~ /^_ref2d/)
|
107
|
+
modifier = token.sub(/_ref2d/, '')
|
108
|
+
_class = _classary[-1]
|
109
|
+
_class = 0 if modifier == 'R'
|
110
|
+
_class = 1 if modifier == 'V'
|
111
|
+
token = args.shift
|
112
|
+
parse_str = parse_str + convert_ref2d(token, _class)
|
113
|
+
elsif (token =~ /^_ref3d/)
|
114
|
+
modifier = token.sub(/_ref3d/,'')
|
115
|
+
_class = _classary[-1]
|
116
|
+
_class = 0 if modifier == 'R'
|
117
|
+
_class = 1 if modifier == 'V'
|
118
|
+
token = args.shift
|
119
|
+
parse_str = parse_str + convert_ref3d(token, _class)
|
120
|
+
elsif (token =~ /^_range2d/)
|
121
|
+
modifier = token.sub(/_range2d/,'')
|
122
|
+
_class = _classary[-1]
|
123
|
+
_class = 0 if modifier == 'R'
|
124
|
+
_class = 1 if modifier == 'V'
|
125
|
+
token = args.shift
|
126
|
+
parse_str = parse_str + convert_range2d(token, _class)
|
127
|
+
elsif (token =~ /^_range3d/)
|
128
|
+
modifier = token.sub(/_range3d/,'')
|
129
|
+
_class = _classary[-1]
|
130
|
+
_class = 0 if modifier == 'R'
|
131
|
+
_class = 1 if modifier == 'V'
|
132
|
+
token = args.shift
|
133
|
+
parse_str = parse_str + convert_range3d(token, _class)
|
134
|
+
elsif (token =~ /^_name/)
|
135
|
+
modifier = token.sub(/_name/, '')
|
136
|
+
_class = _classary[-1]
|
137
|
+
_class = 0 if modifier == 'R'
|
138
|
+
_class = 1 if modifier == 'V'
|
139
|
+
token = args.shift
|
140
|
+
parse_str = parse_str + convert_name(token, _class)
|
141
|
+
elsif (token == '_func')
|
142
|
+
token = args.shift
|
143
|
+
parse_str = parse_str + convert_function(token, num_args.to_i)
|
144
|
+
_classary.pop
|
145
|
+
num_args = 0 # Reset after use
|
146
|
+
elsif @ptg[token]
|
147
|
+
parse_str = parse_str + [@ptg[token]].pack("C")
|
148
|
+
else
|
149
|
+
# Unrecognised token
|
150
|
+
return nil
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
return parse_str
|
155
|
+
end
|
156
|
+
|
157
|
+
def scan(formula)
|
158
|
+
s = StringScanner.new(formula)
|
159
|
+
q = []
|
160
|
+
until s.eos?
|
161
|
+
# order is important.
|
162
|
+
if s.scan(/(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?/)
|
163
|
+
q.push [:NUMBER, s.matched]
|
164
|
+
elsif s.scan(/"([^"]|"")*"/)
|
165
|
+
q.push [:STRING, s.matched]
|
166
|
+
elsif s.scan(/\$?[A-I]?[A-Z]\$?(\d+)?:\$?[A-I]?[A-Z]\$?(\d+)?/)
|
167
|
+
q.push [:RANGE2D , s.matched]
|
168
|
+
elsif s.scan(/[^!(,]+!\$?[A-I]?[A-Z]\$?(\d+)?:\$?[A-I]?[A-Z]\$?(\d+)?/)
|
169
|
+
q.push [:RANGE3D , s.matched]
|
170
|
+
elsif s.scan(/'[^']+'!\$?[A-I]?[A-Z]\$?(\d+)?:\$?[A-I]?[A-Z]\$?(\d+)?/)
|
171
|
+
q.push [:RANGE3D , s.matched]
|
172
|
+
elsif s.scan(/\$?[A-I]?[A-Z]\$?\d+/)
|
173
|
+
q.push [:REF2D, s.matched]
|
174
|
+
elsif s.scan(/[^!(,]+!\$?[A-I]?[A-Z]\$?\d+/)
|
175
|
+
q.push [:REF3D , s.matched]
|
176
|
+
elsif s.scan(/'[^']+'!\$?[A-I]?[A-Z]\$?\d+/)
|
177
|
+
q.push [:REF3D , s.matched]
|
178
|
+
elsif s.scan(/<=/)
|
179
|
+
q.push [:LE , s.matched]
|
180
|
+
elsif s.scan(/>=/)
|
181
|
+
q.push [:GE , s.matched]
|
182
|
+
elsif s.scan(/<>/)
|
183
|
+
q.push [:NE , s.matched]
|
184
|
+
elsif s.scan(/</)
|
185
|
+
q.push [:LT , s.matched]
|
186
|
+
elsif s.scan(/>/)
|
187
|
+
q.push [:GT , s.matched]
|
188
|
+
elsif s.scan(/[A-Z0-9_.]+/)
|
189
|
+
q.push [:FUNC, s.matched]
|
190
|
+
elsif s.scan(/[A-Za-z_]\w+/)
|
191
|
+
q.push [:NAME , s.matched]
|
192
|
+
elsif s.scan(/TRUE/)
|
193
|
+
q.push [:TRUE, s.matched]
|
194
|
+
elsif s.scan(/FALSE/)
|
195
|
+
q.push [:FALSE, s.matched]
|
196
|
+
elsif s.scan(/\s+/)
|
197
|
+
;
|
198
|
+
elsif s.scan(/./)
|
199
|
+
q.push [s.matched, s.matched]
|
200
|
+
end
|
201
|
+
end
|
202
|
+
q.push [:EOL, nil]
|
203
|
+
end
|
204
|
+
|
205
|
+
def parse(formula)
|
206
|
+
@q = scan(formula)
|
207
|
+
@q.push [false, nil]
|
208
|
+
@yydebug=true
|
209
|
+
do_parse
|
210
|
+
end
|
211
|
+
|
212
|
+
def next_token
|
213
|
+
@q.shift
|
214
|
+
end
|
215
|
+
|
216
|
+
def reverse(expression)
|
217
|
+
expression.flatten
|
218
|
+
end
|
219
|
+
|
220
|
+
###############################################################################
|
221
|
+
|
222
|
+
private
|
223
|
+
|
224
|
+
###############################################################################
|
225
|
+
|
226
|
+
|
227
|
+
###############################################################################
|
228
|
+
#
|
229
|
+
# _check_volatile()
|
230
|
+
#
|
231
|
+
# Check if the formula contains a volatile function, i.e. a function that must
|
232
|
+
# be recalculated each time a cell is updated. These formulas require a ptgAttr
|
233
|
+
# with the volatile flag set as the first token in the parsed expression.
|
234
|
+
#
|
235
|
+
# Examples of volatile functions: RAND(), NOW(), TODAY()
|
236
|
+
#
|
237
|
+
def check_volatile(tokens)
|
238
|
+
volatile = 0
|
239
|
+
|
240
|
+
(0..tokens.size-1).each do |i|
|
241
|
+
# If the next token is a function check if it is volatile.
|
242
|
+
if tokens[i] == '_func' and @functions[tokens[i+1]][3] != 0
|
243
|
+
volatile = 1
|
244
|
+
break
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
return volatile
|
249
|
+
end
|
250
|
+
|
251
|
+
###############################################################################
|
252
|
+
#
|
253
|
+
# _convert_volatile()
|
254
|
+
#
|
255
|
+
# Convert _vol to a ptgAttr tag formatted to indicate that the formula contains
|
256
|
+
# a volatile function. See _check_volatile()
|
257
|
+
#
|
258
|
+
def convert_volatile
|
259
|
+
# Set bitFattrSemi flag to indicate volatile function, "w" is set to zero.
|
260
|
+
return [@ptg['ptgAttr'], 0x1, 0x0].pack("CCv")
|
261
|
+
end
|
262
|
+
|
263
|
+
###############################################################################
|
264
|
+
#
|
265
|
+
# _convert_bool()
|
266
|
+
#
|
267
|
+
# Convert a boolean token to ptgBool
|
268
|
+
#
|
269
|
+
def convert_bool(bool)
|
270
|
+
return [@ptg['ptgBool'], bool.to_i].pack("CC")
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
###############################################################################
|
275
|
+
#
|
276
|
+
# _convert_number()
|
277
|
+
#
|
278
|
+
# Convert a number token to ptgInt or ptgNum
|
279
|
+
#
|
280
|
+
def convert_number(num)
|
281
|
+
# Integer in the range 0..2**16-1
|
282
|
+
if ((num =~ /^\d+$/) && (num.to_i <= 65535))
|
283
|
+
return [@ptg['ptgInt'], num.to_i].pack("Cv")
|
284
|
+
else # A float
|
285
|
+
num = [num].pack("d")
|
286
|
+
num.reverse! if @byte_order != 0 && @byte_order != ''
|
287
|
+
return [@ptg['ptgNum']].pack("C") + num
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
###############################################################################
|
292
|
+
#
|
293
|
+
# _convert_string()
|
294
|
+
#
|
295
|
+
# Convert a string to a ptg Str.
|
296
|
+
#
|
297
|
+
def convert_string(str)
|
298
|
+
encoding = 0
|
299
|
+
|
300
|
+
str.sub!(/^"/,'') # Remove leading "
|
301
|
+
str.sub!(/"$/,'') # Remove trailing "
|
302
|
+
str.gsub!(/""/,'"') # Substitute Excel's escaped double quote "" for "
|
303
|
+
|
304
|
+
length = str.length
|
305
|
+
|
306
|
+
# Handle utf8 strings
|
307
|
+
if str =~ NonAscii
|
308
|
+
str = NKF.nkf('-w16L0 -m0 -W', str)
|
309
|
+
encoding = 1
|
310
|
+
end
|
311
|
+
|
312
|
+
exit "String in formula has more than 255 chars\n" if length > 255
|
313
|
+
|
314
|
+
return [@ptg['ptgStr'], length, encoding].pack("CCC") + str
|
315
|
+
end
|
316
|
+
|
317
|
+
###############################################################################
|
318
|
+
#
|
319
|
+
# _convert_ref2d()
|
320
|
+
#
|
321
|
+
# Convert an Excel reference such as A1, $B2, C$3 or $D$4 to a ptgRefV.
|
322
|
+
#
|
323
|
+
def convert_ref2d(cell, _class)
|
324
|
+
# Convert the cell reference
|
325
|
+
row, col = cell_to_packed_rowcol(cell)
|
326
|
+
|
327
|
+
# The ptg value depends on the class of the ptg.
|
328
|
+
if (_class == 0)
|
329
|
+
ptgref = [@ptg['ptgRef']].pack("C")
|
330
|
+
elsif (_class == 1)
|
331
|
+
ptgref = [@ptg['ptgRefV']].pack("C")
|
332
|
+
elsif (_class == 2)
|
333
|
+
ptgref = [@ptg['ptgRefA']].pack("C")
|
334
|
+
else
|
335
|
+
exit "Unknown function class in formula\n"
|
336
|
+
end
|
337
|
+
|
338
|
+
return ptgref + row + col
|
339
|
+
end
|
340
|
+
|
341
|
+
###############################################################################
|
342
|
+
#
|
343
|
+
# _convert_ref3d
|
344
|
+
#
|
345
|
+
# Convert an Excel 3d reference such as "Sheet1!A1" or "Sheet1:Sheet2!A1" to a
|
346
|
+
# ptgRef3dV.
|
347
|
+
#
|
348
|
+
def convert_ref3d(token, _class)
|
349
|
+
# Split the ref at the ! symbol
|
350
|
+
ext_ref, cell = token.split('!')
|
351
|
+
|
352
|
+
# Convert the external reference part
|
353
|
+
ext_ref = pack_ext_ref(ext_ref)
|
354
|
+
|
355
|
+
# Convert the cell reference part
|
356
|
+
row, col = cell_to_packed_rowcol(cell)
|
357
|
+
|
358
|
+
# The ptg value depends on the class of the ptg.
|
359
|
+
if (_class == 0)
|
360
|
+
ptgref = [@ptg['ptgRef3d']].pack("C")
|
361
|
+
elsif (_class == 1)
|
362
|
+
ptgref = [@ptg['ptgRef3dV']].pack("C")
|
363
|
+
elsif (_class == 2)
|
364
|
+
ptgref = [@ptg['ptgRef3dA']].pack("C")
|
365
|
+
else
|
366
|
+
exit "Unknown function class in formula\n"
|
367
|
+
end
|
368
|
+
|
369
|
+
return ptgref + ext_ref + row + col
|
370
|
+
end
|
371
|
+
|
372
|
+
###############################################################################
|
373
|
+
#
|
374
|
+
# _convert_range2d()
|
375
|
+
#
|
376
|
+
# Convert an Excel range such as A1:D4 or A:D to a ptgRefV.
|
377
|
+
#
|
378
|
+
def convert_range2d(range, _class)
|
379
|
+
# Split the range into 2 cell refs
|
380
|
+
cell1, cell2 = range.split(':')
|
381
|
+
|
382
|
+
# A range such as A:D is equivalent to A1:D65536, so add rows as required
|
383
|
+
cell1 = cell1 + '1' unless cell1 =~ /\d/
|
384
|
+
cell2 = cell2 + '65536' unless cell2 =~ /\d/
|
385
|
+
|
386
|
+
# Convert the cell references
|
387
|
+
row1, col1 = cell_to_packed_rowcol(cell1)
|
388
|
+
row2, col2 = cell_to_packed_rowcol(cell2)
|
389
|
+
|
390
|
+
# The ptg value depends on the class of the ptg.
|
391
|
+
if (_class == 0)
|
392
|
+
ptgarea = [@ptg['ptgArea']].pack("C")
|
393
|
+
elsif (_class == 1)
|
394
|
+
ptgarea = [@ptg['ptgAreaV']].pack("C")
|
395
|
+
elsif (_class == 2)
|
396
|
+
ptgarea = [@ptg['ptgAreaA']].pack("C")
|
397
|
+
else
|
398
|
+
exit "Unknown function class in formula\n"
|
399
|
+
end
|
400
|
+
|
401
|
+
return ptgarea + row1 + row2 + col1 + col2
|
402
|
+
end
|
403
|
+
|
404
|
+
###############################################################################
|
405
|
+
#
|
406
|
+
# _convert_range3d
|
407
|
+
#
|
408
|
+
# Convert an Excel 3d range such as "Sheet1!A1:D4" or "Sheet1:Sheet2!A1:D4" to
|
409
|
+
# a ptgArea3dV.
|
410
|
+
#
|
411
|
+
def convert_range3d(token, _class)
|
412
|
+
# Split the ref at the ! symbol
|
413
|
+
ext_ref, range = token.split('!')
|
414
|
+
|
415
|
+
# Convert the external reference part
|
416
|
+
ext_ref = pack_ext_ref(ext_ref)
|
417
|
+
|
418
|
+
# Split the range into 2 cell refs
|
419
|
+
cell1, cell2 = range.split(':')
|
420
|
+
|
421
|
+
# A range such as A:D is equivalent to A1:D65536, so add rows as required
|
422
|
+
cell1 = cell1 + '1' unless cell1 =~ /\d/
|
423
|
+
cell2 = cell2 + '65536' unless cell2 =~ /\d/
|
424
|
+
|
425
|
+
# Convert the cell references
|
426
|
+
row1, col1 = cell_to_packed_rowcol(cell1)
|
427
|
+
row2, col2 = cell_to_packed_rowcol(cell2)
|
428
|
+
|
429
|
+
# The ptg value depends on the class of the ptg.
|
430
|
+
if (_class == 0)
|
431
|
+
ptgarea = [@ptg['ptgArea3d']].pack("C")
|
432
|
+
elsif (_class == 1)
|
433
|
+
ptgarea = [@ptg['ptgArea3dV']].pack("C")
|
434
|
+
elsif (_class == 2)
|
435
|
+
ptgarea = [@ptg['ptgArea3dA']].pack("C")
|
436
|
+
else
|
437
|
+
exit "Unknown function class in formula\n"
|
438
|
+
end
|
439
|
+
|
440
|
+
return ptgarea + ext_ref + row1 + row2 + col1+ col2
|
441
|
+
end
|
442
|
+
|
443
|
+
###############################################################################
|
444
|
+
#
|
445
|
+
# _pack_ext_ref()
|
446
|
+
#
|
447
|
+
# Convert the sheet name part of an external reference, for example "Sheet1" or
|
448
|
+
# "Sheet1:Sheet2", to a packed structure.
|
449
|
+
#
|
450
|
+
def pack_ext_ref(ext_ref)
|
451
|
+
ext_ref.sub!(/^'/,'') # Remove leading ' if any.
|
452
|
+
ext_ref.sub!(/'$/,'') # Remove trailing ' if any.
|
453
|
+
|
454
|
+
# Check if there is a sheet range eg., Sheet1:Sheet2.
|
455
|
+
if (ext_ref =~ /:/)
|
456
|
+
sheet1, sheet2 = ext_ref.split(':')
|
457
|
+
|
458
|
+
sheet1 = get_sheet_index(sheet1)
|
459
|
+
sheet2 = get_sheet_index(sheet2)
|
460
|
+
|
461
|
+
# Reverse max and min sheet numbers if necessary
|
462
|
+
if (sheet1 > sheet2)
|
463
|
+
sheet1, sheet2 = [sheet2, sheet1]
|
464
|
+
end
|
465
|
+
else
|
466
|
+
# Single sheet name only.
|
467
|
+
sheet1, sheet2 = [ext_ref, ext_ref]
|
468
|
+
|
469
|
+
sheet1 = get_sheet_index(sheet1)
|
470
|
+
sheet2 = sheet1
|
471
|
+
end
|
472
|
+
|
473
|
+
key = "#{sheet1}:#{sheet2}"
|
474
|
+
|
475
|
+
if @ext_refs[key].nil?
|
476
|
+
index = get_ext_ref_count
|
477
|
+
@ext_refs[key] = index
|
478
|
+
@ext_ref_count += 1
|
479
|
+
else
|
480
|
+
index = @ext_refs[key]
|
481
|
+
end
|
482
|
+
|
483
|
+
return [index].pack("v")
|
484
|
+
end
|
485
|
+
|
486
|
+
###############################################################################
|
487
|
+
#
|
488
|
+
# _get_sheet_index()
|
489
|
+
#
|
490
|
+
# Look up the index that corresponds to an external sheet name. The hash of
|
491
|
+
# sheet names is updated by the add_worksheet() method of the Workbook class.
|
492
|
+
#
|
493
|
+
def get_sheet_index(sheet_name)
|
494
|
+
# Handle utf8 sheetnames
|
495
|
+
if sheet_name =~ NonAscii
|
496
|
+
sheet_name = NKF.nkf('-w16B0 -m0 -W', sheet_name)
|
497
|
+
end
|
498
|
+
|
499
|
+
if @ext_sheets[sheet_name].nil?
|
500
|
+
raise "Unknown sheet name '#{sheet_name}' in formula\n"
|
501
|
+
else
|
502
|
+
return @ext_sheets[sheet_name]
|
503
|
+
end
|
504
|
+
end
|
505
|
+
public :get_sheet_index
|
506
|
+
|
507
|
+
###############################################################################
|
508
|
+
#
|
509
|
+
# set_ext_sheets()
|
510
|
+
#
|
511
|
+
# This semi-public method is used to update the hash of sheet names. It is
|
512
|
+
# updated by the add_worksheet() method of the Workbook class.
|
513
|
+
#
|
514
|
+
def set_ext_sheets(worksheet, index)
|
515
|
+
# The _ext_sheets hash is used to translate between worksheet names
|
516
|
+
# and their index
|
517
|
+
@ext_sheets[worksheet] = index
|
518
|
+
end
|
519
|
+
public :set_ext_sheets
|
520
|
+
|
521
|
+
###############################################################################
|
522
|
+
#
|
523
|
+
# get_ext_sheets()
|
524
|
+
#
|
525
|
+
# This semi-public method is used to get the worksheet references that were
|
526
|
+
# used in formulas for inclusion in the EXTERNSHEET Workbook record.
|
527
|
+
#
|
528
|
+
def get_ext_sheets
|
529
|
+
@ext_refs
|
530
|
+
end
|
531
|
+
public :get_ext_sheets
|
532
|
+
|
533
|
+
###############################################################################
|
534
|
+
#
|
535
|
+
# get_ext_ref_count()
|
536
|
+
#
|
537
|
+
# TODO This semi-public method is used to update the hash of sheet names. It is
|
538
|
+
# updated by the add_worksheet() method of the Workbook class.
|
539
|
+
#
|
540
|
+
def get_ext_ref_count
|
541
|
+
return @ext_ref_count
|
542
|
+
end
|
543
|
+
|
544
|
+
###############################################################################
|
545
|
+
#
|
546
|
+
# _get_name_index()
|
547
|
+
#
|
548
|
+
# Look up the index that corresponds to an external defined name. The hash of
|
549
|
+
# defined names is updated by the define_name() method in the Workbook class.
|
550
|
+
#
|
551
|
+
def get_name_index(name)
|
552
|
+
if @ext_names.has_key?(name)
|
553
|
+
@ext_names[name]
|
554
|
+
else
|
555
|
+
raise "Unknown defined name $name in formula\n"
|
556
|
+
end
|
557
|
+
end
|
558
|
+
private :get_name_index
|
559
|
+
|
560
|
+
###############################################################################
|
561
|
+
#
|
562
|
+
# set_ext_name()
|
563
|
+
#
|
564
|
+
# This semi-public method is used to update the hash of defined names.
|
565
|
+
#
|
566
|
+
def set_ext_name(name, index)
|
567
|
+
@ext_names[name] = index
|
568
|
+
end
|
569
|
+
public :set_ext_name
|
570
|
+
|
571
|
+
###############################################################################
|
572
|
+
#
|
573
|
+
# _convert_function()
|
574
|
+
#
|
575
|
+
# Convert a function to a ptgFunc or ptgFuncVarV depending on the number of
|
576
|
+
# args that it takes.
|
577
|
+
#
|
578
|
+
def convert_function(token, num_args)
|
579
|
+
exit "Unknown function #{token}() in formula\n" if @functions[token][0].nil?
|
580
|
+
|
581
|
+
args = @functions[token][1]
|
582
|
+
|
583
|
+
# Fixed number of args eg. TIME($i,$j,$k).
|
584
|
+
if (args >= 0)
|
585
|
+
# Check that the number of args is valid.
|
586
|
+
if (args != num_args)
|
587
|
+
raise "Incorrect number of arguments for #{token}() in formula\n";
|
588
|
+
else
|
589
|
+
return [@ptg['ptgFuncV'], @functions[token][0]].pack("Cv")
|
590
|
+
end
|
591
|
+
end
|
592
|
+
|
593
|
+
# Variable number of args eg. SUM(i,j,k, ..).
|
594
|
+
if (args == -1)
|
595
|
+
return [@ptg['ptgFuncVarV'], num_args, @functions[token][0]].pack("CCv")
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
###############################################################################
|
600
|
+
#
|
601
|
+
# _convert_name()
|
602
|
+
#
|
603
|
+
# Convert a symbolic name into a name reference.
|
604
|
+
#
|
605
|
+
def convert_name(name, _class)
|
606
|
+
name_index = get_name_index(name)
|
607
|
+
|
608
|
+
# The ptg value depends on the class of the ptg.
|
609
|
+
if _class == 0
|
610
|
+
ptgName = @ptg['ptgName']
|
611
|
+
elsif _class == 1
|
612
|
+
ptgName = @ptg['ptgNameV']
|
613
|
+
elsif _class == 2
|
614
|
+
ptgName = @ptg['ptgNameA']
|
615
|
+
end
|
616
|
+
|
617
|
+
[ptgName, name_index].pack('CV')
|
618
|
+
end
|
619
|
+
private :convert_name
|
620
|
+
|
621
|
+
###############################################################################
|
622
|
+
#
|
623
|
+
# _cell_to_rowcol($cell_ref)
|
624
|
+
#
|
625
|
+
# Convert an Excel cell reference such as A1 or $B2 or C$3 or $D$4 to a zero
|
626
|
+
# indexed row and column number. Also returns two boolean values to indicate
|
627
|
+
# whether the row or column are relative references.
|
628
|
+
# TODO use function in Utility.pm
|
629
|
+
#
|
630
|
+
def cell_to_rowcol(cell)
|
631
|
+
cell =~ /(\$?)([A-I]?[A-Z])(\$?)(\d+)/
|
632
|
+
|
633
|
+
col_rel = $1 == "" ? 1 : 0
|
634
|
+
col = $2
|
635
|
+
row_rel = $3 == "" ? 1 : 0
|
636
|
+
row = $4.to_i
|
637
|
+
|
638
|
+
# Convert base26 column string to a number.
|
639
|
+
# All your Base are belong to us.
|
640
|
+
chars = col.split(//)
|
641
|
+
expn = 0
|
642
|
+
col = 0
|
643
|
+
|
644
|
+
while (!chars.empty?)
|
645
|
+
char = chars.pop # LS char first
|
646
|
+
col = col + (char[0] - "A"[0] + 1) * (26**expn)
|
647
|
+
expn += 1
|
648
|
+
end
|
649
|
+
# Convert 1-index to zero-index
|
650
|
+
row -= 1
|
651
|
+
col -= 1
|
652
|
+
|
653
|
+
return [row, col, row_rel, col_rel]
|
654
|
+
end
|
655
|
+
|
656
|
+
###############################################################################
|
657
|
+
#
|
658
|
+
# _cell_to_packed_rowcol($row, $col, $row_rel, $col_rel)
|
659
|
+
#
|
660
|
+
# pack() row and column into the required 3 byte format.
|
661
|
+
#
|
662
|
+
def cell_to_packed_rowcol(cell)
|
663
|
+
row, col, row_rel, col_rel = cell_to_rowcol(cell)
|
664
|
+
|
665
|
+
exit "Column #{cell} greater than IV in formula\n" if col >= 256
|
666
|
+
exit "Row #{cell} greater than 65536 in formula\n" if row >= 65536
|
667
|
+
|
668
|
+
# Set the high bits to indicate if row or col are relative.
|
669
|
+
col |= col_rel << 14
|
670
|
+
col |= row_rel << 15
|
671
|
+
|
672
|
+
row = [row].pack('v')
|
673
|
+
col = [col].pack('v')
|
674
|
+
|
675
|
+
return [row, col]
|
676
|
+
end
|
677
|
+
|
678
|
+
###############################################################################
|
679
|
+
#
|
680
|
+
# _initialize_hashes()
|
681
|
+
#
|
682
|
+
def initialize_hashes
|
683
|
+
|
684
|
+
# The Excel ptg indices
|
685
|
+
@ptg = {
|
686
|
+
'ptgExp' => 0x01,
|
687
|
+
'ptgTbl' => 0x02,
|
688
|
+
'ptgAdd' => 0x03,
|
689
|
+
'ptgSub' => 0x04,
|
690
|
+
'ptgMul' => 0x05,
|
691
|
+
'ptgDiv' => 0x06,
|
692
|
+
'ptgPower' => 0x07,
|
693
|
+
'ptgConcat' => 0x08,
|
694
|
+
'ptgLT' => 0x09,
|
695
|
+
'ptgLE' => 0x0A,
|
696
|
+
'ptgEQ' => 0x0B,
|
697
|
+
'ptgGE' => 0x0C,
|
698
|
+
'ptgGT' => 0x0D,
|
699
|
+
'ptgNE' => 0x0E,
|
700
|
+
'ptgIsect' => 0x0F,
|
701
|
+
'ptgUnion' => 0x10,
|
702
|
+
'ptgRange' => 0x11,
|
703
|
+
'ptgUplus' => 0x12,
|
704
|
+
'ptgUminus' => 0x13,
|
705
|
+
'ptgPercent' => 0x14,
|
706
|
+
'ptgParen' => 0x15,
|
707
|
+
'ptgMissArg' => 0x16,
|
708
|
+
'ptgStr' => 0x17,
|
709
|
+
'ptgAttr' => 0x19,
|
710
|
+
'ptgSheet' => 0x1A,
|
711
|
+
'ptgEndSheet' => 0x1B,
|
712
|
+
'ptgErr' => 0x1C,
|
713
|
+
'ptgBool' => 0x1D,
|
714
|
+
'ptgInt' => 0x1E,
|
715
|
+
'ptgNum' => 0x1F,
|
716
|
+
'ptgArray' => 0x20,
|
717
|
+
'ptgFunc' => 0x21,
|
718
|
+
'ptgFuncVar' => 0x22,
|
719
|
+
'ptgName' => 0x23,
|
720
|
+
'ptgRef' => 0x24,
|
721
|
+
'ptgArea' => 0x25,
|
722
|
+
'ptgMemArea' => 0x26,
|
723
|
+
'ptgMemErr' => 0x27,
|
724
|
+
'ptgMemNoMem' => 0x28,
|
725
|
+
'ptgMemFunc' => 0x29,
|
726
|
+
'ptgRefErr' => 0x2A,
|
727
|
+
'ptgAreaErr' => 0x2B,
|
728
|
+
'ptgRefN' => 0x2C,
|
729
|
+
'ptgAreaN' => 0x2D,
|
730
|
+
'ptgMemAreaN' => 0x2E,
|
731
|
+
'ptgMemNoMemN' => 0x2F,
|
732
|
+
'ptgNameX' => 0x39,
|
733
|
+
'ptgRef3d' => 0x3A,
|
734
|
+
'ptgArea3d' => 0x3B,
|
735
|
+
'ptgRefErr3d' => 0x3C,
|
736
|
+
'ptgAreaErr3d' => 0x3D,
|
737
|
+
'ptgArrayV' => 0x40,
|
738
|
+
'ptgFuncV' => 0x41,
|
739
|
+
'ptgFuncVarV' => 0x42,
|
740
|
+
'ptgNameV' => 0x43,
|
741
|
+
'ptgRefV' => 0x44,
|
742
|
+
'ptgAreaV' => 0x45,
|
743
|
+
'ptgMemAreaV' => 0x46,
|
744
|
+
'ptgMemErrV' => 0x47,
|
745
|
+
'ptgMemNoMemV' => 0x48,
|
746
|
+
'ptgMemFuncV' => 0x49,
|
747
|
+
'ptgRefErrV' => 0x4A,
|
748
|
+
'ptgAreaErrV' => 0x4B,
|
749
|
+
'ptgRefNV' => 0x4C,
|
750
|
+
'ptgAreaNV' => 0x4D,
|
751
|
+
'ptgMemAreaNV' => 0x4E,
|
752
|
+
'ptgMemNoMemN' => 0x4F,
|
753
|
+
'ptgFuncCEV' => 0x58,
|
754
|
+
'ptgNameXV' => 0x59,
|
755
|
+
'ptgRef3dV' => 0x5A,
|
756
|
+
'ptgArea3dV' => 0x5B,
|
757
|
+
'ptgRefErr3dV' => 0x5C,
|
758
|
+
'ptgAreaErr3d' => 0x5D,
|
759
|
+
'ptgArrayA' => 0x60,
|
760
|
+
'ptgFuncA' => 0x61,
|
761
|
+
'ptgFuncVarA' => 0x62,
|
762
|
+
'ptgNameA' => 0x63,
|
763
|
+
'ptgRefA' => 0x64,
|
764
|
+
'ptgAreaA' => 0x65,
|
765
|
+
'ptgMemAreaA' => 0x66,
|
766
|
+
'ptgMemErrA' => 0x67,
|
767
|
+
'ptgMemNoMemA' => 0x68,
|
768
|
+
'ptgMemFuncA' => 0x69,
|
769
|
+
'ptgRefErrA' => 0x6A,
|
770
|
+
'ptgAreaErrA' => 0x6B,
|
771
|
+
'ptgRefNA' => 0x6C,
|
772
|
+
'ptgAreaNA' => 0x6D,
|
773
|
+
'ptgMemAreaNA' => 0x6E,
|
774
|
+
'ptgMemNoMemN' => 0x6F,
|
775
|
+
'ptgFuncCEA' => 0x78,
|
776
|
+
'ptgNameXA' => 0x79,
|
777
|
+
'ptgRef3dA' => 0x7A,
|
778
|
+
'ptgArea3dA' => 0x7B,
|
779
|
+
'ptgRefErr3dA' => 0x7C,
|
780
|
+
'ptgAreaErr3d' => 0x7D
|
781
|
+
};
|
782
|
+
|
783
|
+
# Thanks to Michael Meeks and Gnumeric for the initial arg values.
|
784
|
+
#
|
785
|
+
# The following hash was generated by "function_locale.pl" in the distro.
|
786
|
+
# Refer to function_locale.pl for non-English function names.
|
787
|
+
#
|
788
|
+
# The array elements are as follow:
|
789
|
+
# ptg: The Excel function ptg code.
|
790
|
+
# args: The number of arguments that the function takes:
|
791
|
+
# >=0 is a fixed number of arguments.
|
792
|
+
# -1 is a variable number of arguments.
|
793
|
+
# class: The reference, value or array class of the function args.
|
794
|
+
# vol: The function is volatile.
|
795
|
+
#
|
796
|
+
@functions = {
|
797
|
+
# ptg args class vol
|
798
|
+
'COUNT' => [ 0, -1, 0, 0 ],
|
799
|
+
'IF' => [ 1, -1, 1, 0 ],
|
800
|
+
'ISNA' => [ 2, 1, 1, 0 ],
|
801
|
+
'ISERROR' => [ 3, 1, 1, 0 ],
|
802
|
+
'SUM' => [ 4, -1, 0, 0 ],
|
803
|
+
'AVERAGE' => [ 5, -1, 0, 0 ],
|
804
|
+
'MIN' => [ 6, -1, 0, 0 ],
|
805
|
+
'MAX' => [ 7, -1, 0, 0 ],
|
806
|
+
'ROW' => [ 8, -1, 0, 0 ],
|
807
|
+
'COLUMN' => [ 9, -1, 0, 0 ],
|
808
|
+
'NA' => [ 10, 0, 0, 0 ],
|
809
|
+
'NPV' => [ 11, -1, 1, 0 ],
|
810
|
+
'STDEV' => [ 12, -1, 0, 0 ],
|
811
|
+
'DOLLAR' => [ 13, -1, 1, 0 ],
|
812
|
+
'FIXED' => [ 14, -1, 1, 0 ],
|
813
|
+
'SIN' => [ 15, 1, 1, 0 ],
|
814
|
+
'COS' => [ 16, 1, 1, 0 ],
|
815
|
+
'TAN' => [ 17, 1, 1, 0 ],
|
816
|
+
'ATAN' => [ 18, 1, 1, 0 ],
|
817
|
+
'PI' => [ 19, 0, 1, 0 ],
|
818
|
+
'SQRT' => [ 20, 1, 1, 0 ],
|
819
|
+
'EXP' => [ 21, 1, 1, 0 ],
|
820
|
+
'LN' => [ 22, 1, 1, 0 ],
|
821
|
+
'LOG10' => [ 23, 1, 1, 0 ],
|
822
|
+
'ABS' => [ 24, 1, 1, 0 ],
|
823
|
+
'INT' => [ 25, 1, 1, 0 ],
|
824
|
+
'SIGN' => [ 26, 1, 1, 0 ],
|
825
|
+
'ROUND' => [ 27, 2, 1, 0 ],
|
826
|
+
'LOOKUP' => [ 28, -1, 0, 0 ],
|
827
|
+
'INDEX' => [ 29, -1, 0, 1 ],
|
828
|
+
'REPT' => [ 30, 2, 1, 0 ],
|
829
|
+
'MID' => [ 31, 3, 1, 0 ],
|
830
|
+
'LEN' => [ 32, 1, 1, 0 ],
|
831
|
+
'VALUE' => [ 33, 1, 1, 0 ],
|
832
|
+
'TRUE' => [ 34, 0, 1, 0 ],
|
833
|
+
'FALSE' => [ 35, 0, 1, 0 ],
|
834
|
+
'AND' => [ 36, -1, 1, 0 ],
|
835
|
+
'OR' => [ 37, -1, 1, 0 ],
|
836
|
+
'NOT' => [ 38, 1, 1, 0 ],
|
837
|
+
'MOD' => [ 39, 2, 1, 0 ],
|
838
|
+
'DCOUNT' => [ 40, 3, 0, 0 ],
|
839
|
+
'DSUM' => [ 41, 3, 0, 0 ],
|
840
|
+
'DAVERAGE' => [ 42, 3, 0, 0 ],
|
841
|
+
'DMIN' => [ 43, 3, 0, 0 ],
|
842
|
+
'DMAX' => [ 44, 3, 0, 0 ],
|
843
|
+
'DSTDEV' => [ 45, 3, 0, 0 ],
|
844
|
+
'VAR' => [ 46, -1, 0, 0 ],
|
845
|
+
'DVAR' => [ 47, 3, 0, 0 ],
|
846
|
+
'TEXT' => [ 48, 2, 1, 0 ],
|
847
|
+
'LINEST' => [ 49, -1, 0, 0 ],
|
848
|
+
'TREND' => [ 50, -1, 0, 0 ],
|
849
|
+
'LOGEST' => [ 51, -1, 0, 0 ],
|
850
|
+
'GROWTH' => [ 52, -1, 0, 0 ],
|
851
|
+
'PV' => [ 56, -1, 1, 0 ],
|
852
|
+
'FV' => [ 57, -1, 1, 0 ],
|
853
|
+
'NPER' => [ 58, -1, 1, 0 ],
|
854
|
+
'PMT' => [ 59, -1, 1, 0 ],
|
855
|
+
'RATE' => [ 60, -1, 1, 0 ],
|
856
|
+
'MIRR' => [ 61, 3, 0, 0 ],
|
857
|
+
'IRR' => [ 62, -1, 0, 0 ],
|
858
|
+
'RAND' => [ 63, 0, 1, 1 ],
|
859
|
+
'MATCH' => [ 64, -1, 0, 0 ],
|
860
|
+
'DATE' => [ 65, 3, 1, 0 ],
|
861
|
+
'TIME' => [ 66, 3, 1, 0 ],
|
862
|
+
'DAY' => [ 67, 1, 1, 0 ],
|
863
|
+
'MONTH' => [ 68, 1, 1, 0 ],
|
864
|
+
'YEAR' => [ 69, 1, 1, 0 ],
|
865
|
+
'WEEKDAY' => [ 70, -1, 1, 0 ],
|
866
|
+
'HOUR' => [ 71, 1, 1, 0 ],
|
867
|
+
'MINUTE' => [ 72, 1, 1, 0 ],
|
868
|
+
'SECOND' => [ 73, 1, 1, 0 ],
|
869
|
+
'NOW' => [ 74, 0, 1, 1 ],
|
870
|
+
'AREAS' => [ 75, 1, 0, 1 ],
|
871
|
+
'ROWS' => [ 76, 1, 0, 1 ],
|
872
|
+
'COLUMNS' => [ 77, 1, 0, 1 ],
|
873
|
+
'OFFSET' => [ 78, -1, 0, 1 ],
|
874
|
+
'SEARCH' => [ 82, -1, 1, 0 ],
|
875
|
+
'TRANSPOSE' => [ 83, 1, 1, 0 ],
|
876
|
+
'TYPE' => [ 86, 1, 1, 0 ],
|
877
|
+
'ATAN2' => [ 97, 2, 1, 0 ],
|
878
|
+
'ASIN' => [ 98, 1, 1, 0 ],
|
879
|
+
'ACOS' => [ 99, 1, 1, 0 ],
|
880
|
+
'CHOOSE' => [ 100, -1, 1, 0 ],
|
881
|
+
'HLOOKUP' => [ 101, -1, 0, 0 ],
|
882
|
+
'VLOOKUP' => [ 102, -1, 0, 0 ],
|
883
|
+
'ISREF' => [ 105, 1, 0, 0 ],
|
884
|
+
'LOG' => [ 109, -1, 1, 0 ],
|
885
|
+
'CHAR' => [ 111, 1, 1, 0 ],
|
886
|
+
'LOWER' => [ 112, 1, 1, 0 ],
|
887
|
+
'UPPER' => [ 113, 1, 1, 0 ],
|
888
|
+
'PROPER' => [ 114, 1, 1, 0 ],
|
889
|
+
'LEFT' => [ 115, -1, 1, 0 ],
|
890
|
+
'RIGHT' => [ 116, -1, 1, 0 ],
|
891
|
+
'EXACT' => [ 117, 2, 1, 0 ],
|
892
|
+
'TRIM' => [ 118, 1, 1, 0 ],
|
893
|
+
'REPLACE' => [ 119, 4, 1, 0 ],
|
894
|
+
'SUBSTITUTE' => [ 120, -1, 1, 0 ],
|
895
|
+
'CODE' => [ 121, 1, 1, 0 ],
|
896
|
+
'FIND' => [ 124, -1, 1, 0 ],
|
897
|
+
'CELL' => [ 125, -1, 0, 1 ],
|
898
|
+
'ISERR' => [ 126, 1, 1, 0 ],
|
899
|
+
'ISTEXT' => [ 127, 1, 1, 0 ],
|
900
|
+
'ISNUMBER' => [ 128, 1, 1, 0 ],
|
901
|
+
'ISBLANK' => [ 129, 1, 1, 0 ],
|
902
|
+
'T' => [ 130, 1, 0, 0 ],
|
903
|
+
'N' => [ 131, 1, 0, 0 ],
|
904
|
+
'DATEVALUE' => [ 140, 1, 1, 0 ],
|
905
|
+
'TIMEVALUE' => [ 141, 1, 1, 0 ],
|
906
|
+
'SLN' => [ 142, 3, 1, 0 ],
|
907
|
+
'SYD' => [ 143, 4, 1, 0 ],
|
908
|
+
'DDB' => [ 144, -1, 1, 0 ],
|
909
|
+
'INDIRECT' => [ 148, -1, 1, 1 ],
|
910
|
+
'CALL' => [ 150, -1, 1, 0 ],
|
911
|
+
'CLEAN' => [ 162, 1, 1, 0 ],
|
912
|
+
'MDETERM' => [ 163, 1, 2, 0 ],
|
913
|
+
'MINVERSE' => [ 164, 1, 2, 0 ],
|
914
|
+
'MMULT' => [ 165, 2, 2, 0 ],
|
915
|
+
'IPMT' => [ 167, -1, 1, 0 ],
|
916
|
+
'PPMT' => [ 168, -1, 1, 0 ],
|
917
|
+
'COUNTA' => [ 169, -1, 0, 0 ],
|
918
|
+
'PRODUCT' => [ 183, -1, 0, 0 ],
|
919
|
+
'FACT' => [ 184, 1, 1, 0 ],
|
920
|
+
'DPRODUCT' => [ 189, 3, 0, 0 ],
|
921
|
+
'ISNONTEXT' => [ 190, 1, 1, 0 ],
|
922
|
+
'STDEVP' => [ 193, -1, 0, 0 ],
|
923
|
+
'VARP' => [ 194, -1, 0, 0 ],
|
924
|
+
'DSTDEVP' => [ 195, 3, 0, 0 ],
|
925
|
+
'DVARP' => [ 196, 3, 0, 0 ],
|
926
|
+
'TRUNC' => [ 197, -1, 1, 0 ],
|
927
|
+
'ISLOGICAL' => [ 198, 1, 1, 0 ],
|
928
|
+
'DCOUNTA' => [ 199, 3, 0, 0 ],
|
929
|
+
'ROUNDUP' => [ 212, 2, 1, 0 ],
|
930
|
+
'ROUNDDOWN' => [ 213, 2, 1, 0 ],
|
931
|
+
'RANK' => [ 216, -1, 0, 0 ],
|
932
|
+
'ADDRESS' => [ 219, -1, 1, 0 ],
|
933
|
+
'DAYS360' => [ 220, -1, 1, 0 ],
|
934
|
+
'TODAY' => [ 221, 0, 1, 1 ],
|
935
|
+
'VDB' => [ 222, -1, 1, 0 ],
|
936
|
+
'MEDIAN' => [ 227, -1, 0, 0 ],
|
937
|
+
'SUMPRODUCT' => [ 228, -1, 2, 0 ],
|
938
|
+
'SINH' => [ 229, 1, 1, 0 ],
|
939
|
+
'COSH' => [ 230, 1, 1, 0 ],
|
940
|
+
'TANH' => [ 231, 1, 1, 0 ],
|
941
|
+
'ASINH' => [ 232, 1, 1, 0 ],
|
942
|
+
'ACOSH' => [ 233, 1, 1, 0 ],
|
943
|
+
'ATANH' => [ 234, 1, 1, 0 ],
|
944
|
+
'DGET' => [ 235, 3, 0, 0 ],
|
945
|
+
'INFO' => [ 244, 1, 1, 1 ],
|
946
|
+
'DB' => [ 247, -1, 1, 0 ],
|
947
|
+
'FREQUENCY' => [ 252, 2, 0, 0 ],
|
948
|
+
'ERROR.TYPE' => [ 261, 1, 1, 0 ],
|
949
|
+
'REGISTER.ID' => [ 267, -1, 1, 0 ],
|
950
|
+
'AVEDEV' => [ 269, -1, 0, 0 ],
|
951
|
+
'BETADIST' => [ 270, -1, 1, 0 ],
|
952
|
+
'GAMMALN' => [ 271, 1, 1, 0 ],
|
953
|
+
'BETAINV' => [ 272, -1, 1, 0 ],
|
954
|
+
'BINOMDIST' => [ 273, 4, 1, 0 ],
|
955
|
+
'CHIDIST' => [ 274, 2, 1, 0 ],
|
956
|
+
'CHIINV' => [ 275, 2, 1, 0 ],
|
957
|
+
'COMBIN' => [ 276, 2, 1, 0 ],
|
958
|
+
'CONFIDENCE' => [ 277, 3, 1, 0 ],
|
959
|
+
'CRITBINOM' => [ 278, 3, 1, 0 ],
|
960
|
+
'EVEN' => [ 279, 1, 1, 0 ],
|
961
|
+
'EXPONDIST' => [ 280, 3, 1, 0 ],
|
962
|
+
'FDIST' => [ 281, 3, 1, 0 ],
|
963
|
+
'FINV' => [ 282, 3, 1, 0 ],
|
964
|
+
'FISHER' => [ 283, 1, 1, 0 ],
|
965
|
+
'FISHERINV' => [ 284, 1, 1, 0 ],
|
966
|
+
'FLOOR' => [ 285, 2, 1, 0 ],
|
967
|
+
'GAMMADIST' => [ 286, 4, 1, 0 ],
|
968
|
+
'GAMMAINV' => [ 287, 3, 1, 0 ],
|
969
|
+
'CEILING' => [ 288, 2, 1, 0 ],
|
970
|
+
'HYPGEOMDIST' => [ 289, 4, 1, 0 ],
|
971
|
+
'LOGNORMDIST' => [ 290, 3, 1, 0 ],
|
972
|
+
'LOGINV' => [ 291, 3, 1, 0 ],
|
973
|
+
'NEGBINOMDIST' => [ 292, 3, 1, 0 ],
|
974
|
+
'NORMDIST' => [ 293, 4, 1, 0 ],
|
975
|
+
'NORMSDIST' => [ 294, 1, 1, 0 ],
|
976
|
+
'NORMINV' => [ 295, 3, 1, 0 ],
|
977
|
+
'NORMSINV' => [ 296, 1, 1, 0 ],
|
978
|
+
'STANDARDIZE' => [ 297, 3, 1, 0 ],
|
979
|
+
'ODD' => [ 298, 1, 1, 0 ],
|
980
|
+
'PERMUT' => [ 299, 2, 1, 0 ],
|
981
|
+
'POISSON' => [ 300, 3, 1, 0 ],
|
982
|
+
'TDIST' => [ 301, 3, 1, 0 ],
|
983
|
+
'WEIBULL' => [ 302, 4, 1, 0 ],
|
984
|
+
'SUMXMY2' => [ 303, 2, 2, 0 ],
|
985
|
+
'SUMX2MY2' => [ 304, 2, 2, 0 ],
|
986
|
+
'SUMX2PY2' => [ 305, 2, 2, 0 ],
|
987
|
+
'CHITEST' => [ 306, 2, 2, 0 ],
|
988
|
+
'CORREL' => [ 307, 2, 2, 0 ],
|
989
|
+
'COVAR' => [ 308, 2, 2, 0 ],
|
990
|
+
'FORECAST' => [ 309, 3, 2, 0 ],
|
991
|
+
'FTEST' => [ 310, 2, 2, 0 ],
|
992
|
+
'INTERCEPT' => [ 311, 2, 2, 0 ],
|
993
|
+
'PEARSON' => [ 312, 2, 2, 0 ],
|
994
|
+
'RSQ' => [ 313, 2, 2, 0 ],
|
995
|
+
'STEYX' => [ 314, 2, 2, 0 ],
|
996
|
+
'SLOPE' => [ 315, 2, 2, 0 ],
|
997
|
+
'TTEST' => [ 316, 4, 2, 0 ],
|
998
|
+
'PROB' => [ 317, -1, 2, 0 ],
|
999
|
+
'DEVSQ' => [ 318, -1, 0, 0 ],
|
1000
|
+
'GEOMEAN' => [ 319, -1, 0, 0 ],
|
1001
|
+
'HARMEAN' => [ 320, -1, 0, 0 ],
|
1002
|
+
'SUMSQ' => [ 321, -1, 0, 0 ],
|
1003
|
+
'KURT' => [ 322, -1, 0, 0 ],
|
1004
|
+
'SKEW' => [ 323, -1, 0, 0 ],
|
1005
|
+
'ZTEST' => [ 324, -1, 0, 0 ],
|
1006
|
+
'LARGE' => [ 325, 2, 0, 0 ],
|
1007
|
+
'SMALL' => [ 326, 2, 0, 0 ],
|
1008
|
+
'QUARTILE' => [ 327, 2, 0, 0 ],
|
1009
|
+
'PERCENTILE' => [ 328, 2, 0, 0 ],
|
1010
|
+
'PERCENTRANK' => [ 329, -1, 0, 0 ],
|
1011
|
+
'MODE' => [ 330, -1, 2, 0 ],
|
1012
|
+
'TRIMMEAN' => [ 331, 2, 0, 0 ],
|
1013
|
+
'TINV' => [ 332, 2, 1, 0 ],
|
1014
|
+
'CONCATENATE' => [ 336, -1, 1, 0 ],
|
1015
|
+
'POWER' => [ 337, 2, 1, 0 ],
|
1016
|
+
'RADIANS' => [ 342, 1, 1, 0 ],
|
1017
|
+
'DEGREES' => [ 343, 1, 1, 0 ],
|
1018
|
+
'SUBTOTAL' => [ 344, -1, 0, 0 ],
|
1019
|
+
'SUMIF' => [ 345, -1, 0, 0 ],
|
1020
|
+
'COUNTIF' => [ 346, 2, 0, 0 ],
|
1021
|
+
'COUNTBLANK' => [ 347, 1, 0, 0 ],
|
1022
|
+
'ROMAN' => [ 354, -1, 1, 0 ]
|
1023
|
+
}
|
1024
|
+
|
1025
|
+
end
|
1026
|
+
|
1027
|
+
|
1028
|
+
end
|
1029
|
+
|
1030
|
+
if $0 ==__FILE__
|
1031
|
+
|
1032
|
+
|
1033
|
+
parser = Formula.new
|
1034
|
+
puts
|
1035
|
+
puts 'type "Q" to quit.'
|
1036
|
+
puts
|
1037
|
+
while true
|
1038
|
+
puts
|
1039
|
+
print '? '
|
1040
|
+
str = gets.chop!
|
1041
|
+
break if /q/i =~ str
|
1042
|
+
begin
|
1043
|
+
e = parser.parse(str)
|
1044
|
+
p parser.reverse(e)
|
1045
|
+
rescue ParseError
|
1046
|
+
puts $!
|
1047
|
+
end
|
1048
|
+
end
|
1049
|
+
|
1050
|
+
end
|