Method: Writeexcel::Worksheet#write_formula
- Defined in:
- lib/writeexcel/worksheet.rb
#write_formula(*args) ⇒ Object
:call-seq:
write_formula(row, col , formula[, format, value]) -> Fixnum
write_formula(A1_notation, formula[, format, value]) -> Fixnum
Write a formula to the specified row and column (zero indexed).
format is optional. value is an optional result of the formula that can be supplied by the user.
Returns 0 : normal termination
-1 : insufficient number of arguments
-2 : row or column out of range
Write a formula or function to the cell specified by row and column:
worksheet.write_formula(0, 0, '=$B$3 + B4' )
worksheet.write_formula(1, 0, '=SIN(PI()/4)')
worksheet.write_formula(2, 0, '=SUM(B1:B5)' )
worksheet.write_formula('A4', '=IF(A3>1,"Yes", "No")' )
worksheet.write_formula('A5', '=AVERAGE(1, 2, 3, 4)' )
worksheet.write_formula('A6', '=DATEVALUE("1-Jan-2001")')
See the note about “Cell notation”. For more information about writing Excel formulas see “FORMULAS AND FUNCTIONS IN EXCEL”
See also the section “Improving performance when working with formulas” and the store_formula() and repeat_formula() methods.
If required, it is also possible to specify the calculated value of the formula. This is occasionally necessary when working with non-Excel applications that don’t calculated the value of the formula. The calculated value is added at the end of the argument list:
worksheet.write('A1', '=2+2', format, 4);
However, this probably isn’t something that will ever need to do. If you do use this feature then do so with care.
FORMULAS AND FUNCTIONS IN EXCEL
Caveats
The first thing to note is that there are still some outstanding issues with the implementation of formulas and functions:
1. Writing a formula is much slower than writing the equivalent string.
2. You cannot use array constants, i.e. {1;2;3}, in functions.
3. Unary minus isn't supported.
4. Whitespace is not preserved around operators.
5. Named ranges are not supported.
6. Array formulas are not supported.
However, these constraints will be removed in future versions. They are here because of a trade-off between features and time. Also, it is possible to work around issue 1 using the store_formula() and repeat_formula() methods as described later in this section.
Introduction
The following is a brief introduction to formulas and functions in Excel and WriteExcel.
A formula is a string that begins with an equals sign:
'=A1+B1'
'=AVERAGE(1, 2, 3)'
The formula can contain numbers, strings, boolean values, cell references, cell ranges and functions. Named ranges are not supported. Formulas should be written as they appear in Excel, that is cells and functions must be in uppercase.
Cells in Excel are referenced using the A1 notation system where the column is designated by a letter and the row by a number. Columns range from A to IV i.e. 0 to 255, rows range from 1 to 65536.
The Excel $ notation in cell references is also supported. This allows you to specify whether a row or column is relative or absolute. This only has an effect if the cell is copied. The following examples show relative and absolute values.
'=A1' # Column and row are relative
'=$A1' # Column is absolute and row is relative
'=A$1' # Column is relative and row is absolute
'=$A$1' # Column and row are absolute
Formulas can also refer to cells in other worksheets of the current workbook. For example:
'=Sheet2!A1'
'=Sheet2!A1:A5'
'=Sheet2:Sheet3!A1'
'=Sheet2:Sheet3!A1:A5'
%q{='Test Data'!A1}
%q{='Test Data1:Test Data2'!A1}
The sheet reference and the cell reference are separated by ! the exclamation mark symbol. If worksheet names contain spaces, commas o parentheses then Excel requires that the name is enclosed in single quotes as shown in the last two examples above. In order to avoid using a lot of escape characters you can use the quote operator %q{} to protect the quotes. See perlop in the main Perl documentation. Only valid sheet names that have been added using the add_worksheet() method can be used in formulas. You cannot reference external workbooks.
The following table lists the operators that are available in Excel’s formulas. The majority of the operators are the same as Perl’s, differences are indicated:
Arithmetic operators:
=====================
Operator Meaning Example
+ Addition 1+2
- Subtraction 2-1
* Multiplication 2*3
/ Division 1/4
^ Exponentiation 2^3 # Equivalent to **
- Unary minus -(1+2) # Not yet supported
% Percent (Not modulus) 13% # Not supported, [1]
Comparison operators:
=====================
Operator Meaning Example
= Equal to A1 = B1 # Equivalent to ==
<> Not equal to A1 <> B1 # Equivalent to !=
> Greater than A1 > B1
< Less than A1 < B1
>= Greater than or equal to A1 >= B1
<= Less than or equal to A1 <= B1
String operator:
================
Operator Meaning Example
& Concatenation "Hello " & "World!" # [2]
Reference operators:
====================
Operator Meaning Example
: Range operator A1:A4 # [3]
, Union operator SUM(1, 2+2, B3) # [4]
Notes:
[1]: You can get a percentage with formatting and modulus with MOD().
[2]: Equivalent to ("Hello " . "World!") in Perl.
[3]: This range is equivalent to cells A1, A2, A3 and A4.
[4]: The comma behaves like the list separator in Perl.
The range and comma operators can have different symbols in non-English versions of Excel. These will be supported in a later version of WriteExcel. European users of Excel take note:
worksheet.write('A1', '=SUM(1; 2; 3)') # Wrong!!
worksheet.write('A1', '=SUM(1, 2, 3)') # Okay
The following table lists all of the core functions supported by Excel 5 and WriteExcel. Any additional functions that are available through the “Analysis ToolPak” or other add-ins are not supported. These functions have all been tested to verify that they work.
ABS DB INDIRECT NORMINV SLN
ACOS DCOUNT INFO NORMSDIST SLOPE
ACOSH DCOUNTA INT NORMSINV SMALL
ADDRESS DDB INTERCEPT NOT SQRT
AND DEGREES IPMT NOW STANDARDIZE
AREAS DEVSQ IRR NPER STDEV
ASIN DGET ISBLANK NPV STDEVP
ASINH DMAX ISERR ODD STEYX
ATAN DMIN ISERROR OFFSET SUBSTITUTE
ATAN2 DOLLAR ISLOGICAL OR SUBTOTAL
ATANH DPRODUCT ISNA PEARSON SUM
AVEDEV DSTDEV ISNONTEXT PERCENTILE SUMIF
AVERAGE DSTDEVP ISNUMBER PERCENTRANK SUMPRODUCT
BETADIST DSUM ISREF PERMUT SUMSQ
BETAINV DVAR ISTEXT PI SUMX2MY2
BINOMDIST DVARP KURT PMT SUMX2PY2
CALL ERROR.TYPE LARGE POISSON SUMXMY2
CEILING EVEN LEFT POWER SYD
CELL EXACT LEN PPMT T
CHAR EXP LINEST PROB TAN
CHIDIST EXPONDIST LN PRODUCT TANH
CHIINV FACT LOG PROPER TDIST
CHITEST FALSE LOG10 PV TEXT
CHOOSE FDIST LOGEST QUARTILE TIME
CLEAN FIND LOGINV RADIANS TIMEVALUE
CODE FINV LOGNORMDIST RAND TINV
COLUMN FISHER LOOKUP RANK TODAY
COLUMNS FISHERINV LOWER RATE TRANSPOSE
COMBIN FIXED MATCH REGISTER.ID TREND
CONCATENATE FLOOR MAX REPLACE TRIM
CONFIDENCE FORECAST MDETERM REPT TRIMMEAN
CORREL FREQUENCY MEDIAN RIGHT TRUE
COS FTEST MID ROMAN TRUNC
COSH FV MIN ROUND TTEST
COUNT GAMMADIST MINUTE ROUNDDOWN TYPE
COUNTA GAMMAINV MINVERSE ROUNDUP UPPER
COUNTBLANK GAMMALN MIRR ROW VALUE
COUNTIF GEOMEAN MMULT ROWS VAR
COVAR GROWTH MOD RSQ VARP
CRITBINOM HARMEAN MODE SEARCH VDB
DATE HLOOKUP MONTH SECOND VLOOKUP
DATEVALUE HOUR N SIGN WEEKDAY
DAVERAGE HYPGEOMDIST NA SIN WEIBULL
DAY IF NEGBINOMDIST SINH YEAR
DAYS360 INDEX NORMDIST SKEW ZTEST
– You can also modify the module to support function names in the following languages: German, French, Spanish, Portuguese, Dutch, Finnish, Italian and Swedish. See the function_locale.pl program in the examples directory of the distro. ++
For a general introduction to Excel’s formulas and an explanation of the syntax of the function refer to the Excel help files or the following: office.microsoft.com/en-us/assistance/CH062528031033.aspx
If your formula doesn’t work in WriteExcel try the following:
1. Verify that the formula works in Excel (or Gnumeric or OpenOffice.org).
2. Ensure that it isn't on the Caveats list shown above.
3. Ensure that cell references and formula names are in uppercase.
4. Ensure that you are using ':' as the range operator, A1:A4.
5. Ensure that you are using ',' as the union operator, SUM(1,2,3).
6. Ensure that the function is in the above table.
If you go through steps 1-6 and you still have a problem, mail me.
Improving performance when working with formulas
Writing a large number of formulas with WriteExcel can be slow. This is due to the fact that each formula has to be parsed and with the current implementation this is computationally expensive.
However, in a lot of cases the formulas that you write will be quite similar, for example:
worksheet.write_formula('B1', '=A1 * 3 + 50', format)
worksheet.write_formula('B2', '=A2 * 3 + 50', format)
...
...
worksheet.write_formula('B99', '=A999 * 3 + 50', format)
worksheet.write_formula('B1000', '=A1000 * 3 + 50', format)
In this example the cell reference changes in iterations from A1 to A1000. The parser treats this variable as a token and arranges it according to predefined rules. However, since the parser is oblivious to the value of the token, it is essentially performing the same calculation 1000 times. This is inefficient.
The way to avoid this inefficiency and thereby speed up the writing of formulas is to parse the formula once and then repeatedly substitute similar tokens.
A formula can be parsed and stored via the store_formula() worksheet method. You can then use the repeat_formula() method to substitute pattern, replace pairs in the stored formula:
formula = worksheet.store_formula('=A1 * 3 + 50')
(0...1000).each do |row|
worksheet.repeat_formula(row, 1, formula, format, 'A1', 'A'.(row +1))
end
On an arbitrary test machine this method was 10 times faster than the brute force method shown above. – For more information about how WriteExcel parses and stores formulas see the WriteExcel::Formula man page.
It should be noted however that the overall speed of direct formula parsing will be improved in a future version. ++
2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 |
# File 'lib/writeexcel/worksheet.rb', line 2833 def write_formula(*args) # Check for a cell reference in A1 notation and substitute row and column args = row_col_notation(args) return -1 if args.size < 3 # Check the number of args row, col, formula, format, value = args # Check that row and col are valid and store max and min values return -2 unless check_dimensions(row, col) == 0 xf = xf_record_index(row, col, format) # The cell format # Strip the = sign at the beginning of the formula string formula = formula.sub(/^=/, '') # Parse the formula using the parser in Formula.pm # nakamura add: to get byte_stream, set second arg TRUE # because ruby doesn't have Perl's "wantarray" formula = parser.parse_formula(formula, true) store_formula_common(row, col, xf, value, formula) 0 end |