<changes>
<release version="3.8-beta1" date="2010-??-??">
+ <action dev="POI-DEVELOPERS" type="add">50607 - Added implementation for CLEAN(), CHAR() and ADDRESS()</action>
<action dev="poi-developers" type="add">50587 - Improved documentation on user-defined functions</action>
<action dev="poi-developers" type="add">Inside ExtractorFactory, support finding embedded OOXML documents and providing extractors for them</action>
<action dev="poi-developers" type="add">Partial HDGF LZW compression support</action>
retval[109] = NumericFunction.LOG;
+ retval[111] = TextFunction.CHAR;
retval[112] = TextFunction.LOWER;
retval[113] = TextFunction.UPPER;
retval[130] = new T();
retval[ID.INDIRECT] = null; // Indirect.evaluate has different signature
-
+ retval[162] = TextFunction.CLEAN; //Aniket Banerjee
retval[169] = new Counta();
retval[183] = AggregateFunction.PRODUCT;
retval[212] = NumericFunction.ROUNDUP;
retval[213] = NumericFunction.ROUNDDOWN;
-
+ retval[219] = new Address(); //Aniket Banerjee
retval[220] = new Days360();
retval[221] = new Today();
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.ss.formula.functions;\r
+\r
+import org.apache.poi.ss.formula.SheetNameFormatter;\r
+import org.apache.poi.ss.formula.eval.*;\r
+import org.apache.poi.ss.util.CellReference;\r
+\r
+/**\r
+ * Creates a text reference as text, given specified row and column numbers.\r
+ *\r
+ * @author Aniket Banerjee (banerjee@google.com)\r
+ */\r
+public class Address implements Function {\r
+ public static final int REF_ABSOLUTE = 1;\r
+ public static final int REF_ROW_ABSOLUTE_COLUMN_RELATIVE = 2;\r
+ public static final int REF_ROW_RELATIVE_RELATIVE_ABSOLUTE = 3;\r
+ public static final int REF_RELATIVE = 4;\r
+\r
+ public ValueEval evaluate(ValueEval[] args, int srcRowIndex,\r
+ int srcColumnIndex) {\r
+ if(args.length < 2 || args.length > 5) {\r
+ return ErrorEval.VALUE_INVALID;\r
+ }\r
+ try {\r
+ boolean pAbsRow, pAbsCol;\r
+\r
+ int row = (int)NumericFunction.singleOperandEvaluate(args[0], srcRowIndex, srcColumnIndex);\r
+ int col = (int)NumericFunction.singleOperandEvaluate(args[1], srcRowIndex, srcColumnIndex);\r
+\r
+ int refType;\r
+ if(args.length > 2){\r
+ refType = (int)NumericFunction.singleOperandEvaluate(args[2], srcRowIndex, srcColumnIndex);\r
+ } else {\r
+ refType = REF_ABSOLUTE;\r
+ }\r
+ switch (refType){\r
+ case REF_ABSOLUTE:\r
+ pAbsRow = true;\r
+ pAbsCol = true;\r
+ break;\r
+ case REF_ROW_ABSOLUTE_COLUMN_RELATIVE:\r
+ pAbsRow = true;\r
+ pAbsCol = false;\r
+ break;\r
+ case REF_ROW_RELATIVE_RELATIVE_ABSOLUTE:\r
+ pAbsRow = false;\r
+ pAbsCol = true;\r
+ break;\r
+ case REF_RELATIVE:\r
+ pAbsRow = false;\r
+ pAbsCol = false;\r
+ break;\r
+ default:\r
+ throw new EvaluationException(ErrorEval.VALUE_INVALID);\r
+ }\r
+\r
+ boolean a1;\r
+ if(args.length > 3){\r
+ ValueEval ve = OperandResolver.getSingleValue(args[3], srcRowIndex, srcColumnIndex);\r
+ // TODO R1C1 style is not yet supported\r
+ a1 = ve == MissingArgEval.instance ? true : OperandResolver.coerceValueToBoolean(ve, false);\r
+ } else {\r
+ a1 = true;\r
+ }\r
+\r
+ String sheetName;\r
+ if(args.length == 5){\r
+ ValueEval ve = OperandResolver.getSingleValue(args[4], srcRowIndex, srcColumnIndex);\r
+ sheetName = ve == MissingArgEval.instance ? null : OperandResolver.coerceValueToString(ve);\r
+ } else {\r
+ sheetName = null;\r
+ }\r
+\r
+ CellReference ref = new CellReference(row - 1, col - 1, pAbsRow, pAbsCol);\r
+ StringBuffer sb = new StringBuffer(32);\r
+ if(sheetName != null) {\r
+ SheetNameFormatter.appendFormat(sb, sheetName);\r
+ sb.append('!');\r
+ }\r
+ sb.append(ref.formatAsString());\r
+\r
+ return new StringEval(sb.toString());\r
+\r
+ } catch (EvaluationException e){\r
+ return e.getErrorEval();\r
+ }\r
+ }\r
+}\r
protected abstract ValueEval evaluate(String arg);
}
+ /**
+ * Returns the character specified by a number.
+ */
+ public static final Function CHAR = new Fixed1ArgFunction() {
+ public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
+ int arg;
+ try {
+ arg = evaluateIntArg(arg0, srcRowIndex, srcColumnIndex);
+ if (arg < 0 || arg >= 256) {
+ throw new EvaluationException(ErrorEval.VALUE_INVALID);
+ }
+
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+ return new StringEval(String.valueOf((char)arg));
+ }
+ };
+
public static final Function LEN = new SingleArgTextFunc() {
protected ValueEval evaluate(String arg) {
return new NumberEval(arg.length());
return new StringEval(arg.trim());
}
};
-
+
/**
+ * An implementation of the CLEAN function:
+ * In Excel, the Clean function removes all non-printable characters from a string.
+ *
+ * Author: Aniket Banerjee(banerjee@google.com)
+ */
+ public static final Function CLEAN = new SingleArgTextFunc() {
+ protected ValueEval evaluate(String arg) {
+ StringBuilder result = new StringBuilder();
+ for (int i = 0; i < arg.length(); i++) {
+ char c = arg.charAt(i);
+ if (isPrintable(c)) {
+ result.append(c);
+ }
+ }
+ return new StringEval(result.toString());
+ }
+
+ /**
+ * From Excel docs: The CLEAN function was designed to remove the first 32 nonprinting characters
+ * in the 7-bit ASCII code (values 0 through 31) from text. In the Unicode character set,
+ * there are additional nonprinting characters (values 127, 129, 141, 143, 144, and 157). By itself,
+ * the CLEAN function does not remove these additional nonprinting characters. To do this task,
+ * use the SUBSTITUTE function to replace the higher value Unicode characters with the 7-bit ASCII
+ * characters for which the TRIM and CLEAN functions were designed.
+ *
+ * @param c the character to test
+ * @return whether the character is printable
+ */
+ private boolean isPrintable(char c){
+ int charCode = (int)c ;
+ return charCode >= 32;
+ }
+ };
+
+ /**
* An implementation of the MID function<br/>
* MID returns a specific number of
* characters from a text string, starting at the specified position.<p/>
result.addTestSuite(TestTrunc.class);
result.addTestSuite(TestValue.class);
result.addTestSuite(TestXYNumericFunction.class);
+ result.addTestSuite(TestAddress.class);
+ result.addTestSuite(TestClean.class);
return result;
}
}
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.ss.formula.functions;\r
+\r
+import org.apache.poi.hssf.usermodel.HSSFCell;\r
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;\r
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;\r
+import org.apache.poi.ss.usermodel.CellValue;\r
+\r
+import junit.framework.TestCase;\r
+import org.apache.poi.ss.util.CellReference;\r
+\r
+public final class TestAddress extends TestCase {\r
+\r
+ public void testAddress() {\r
+ HSSFWorkbook wb = new HSSFWorkbook();\r
+ HSSFCell cell = wb.createSheet().createRow(0).createCell(0);\r
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);\r
+\r
+ String formulaText = "ADDRESS(1,2)";\r
+ confirmResult(fe, cell, formulaText, "$B$1");\r
+\r
+ formulaText = "ADDRESS(22,44)";\r
+ confirmResult(fe, cell, formulaText, "$AR$22");\r
+\r
+ formulaText = "ADDRESS(1,1)";\r
+ confirmResult(fe, cell, formulaText, "$A$1");\r
+\r
+ formulaText = "ADDRESS(1,128)";\r
+ confirmResult(fe, cell, formulaText, "$DX$1");\r
+\r
+ formulaText = "ADDRESS(1,512)";\r
+ confirmResult(fe, cell, formulaText, "$SR$1");\r
+\r
+ formulaText = "ADDRESS(1,1000)";\r
+ confirmResult(fe, cell, formulaText, "$ALL$1");\r
+\r
+ formulaText = "ADDRESS(1,10000)";\r
+ confirmResult(fe, cell, formulaText, "$NTP$1");\r
+\r
+ formulaText = "ADDRESS(2,3)";\r
+ confirmResult(fe, cell, formulaText, "$C$2");\r
+\r
+ formulaText = "ADDRESS(2,3,2)";\r
+ confirmResult(fe, cell, formulaText, "C$2");\r
+\r
+ formulaText = "ADDRESS(2,3,2,,\"EXCEL SHEET\")";\r
+ confirmResult(fe, cell, formulaText, "'EXCEL SHEET'!C$2");\r
+\r
+ formulaText = "ADDRESS(2,3,3,TRUE,\"[Book1]Sheet1\")";\r
+ confirmResult(fe, cell, formulaText, "'[Book1]Sheet1'!$C2");\r
+ }\r
+\r
+ private static void confirmResult(HSSFFormulaEvaluator fe, HSSFCell cell, String formulaText,\r
+ String expectedResult) {\r
+ cell.setCellFormula(formulaText);\r
+ fe.notifyUpdateCell(cell);\r
+ CellValue result = fe.evaluate(cell);\r
+ assertEquals(result.getCellType(), HSSFCell.CELL_TYPE_STRING);\r
+ assertEquals(expectedResult, result.getStringValue());\r
+ }\r
+}\r
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.ss.formula.functions;\r
+\r
+import org.apache.poi.hssf.usermodel.HSSFCell;\r
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;\r
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;\r
+import org.apache.poi.ss.usermodel.CellValue;\r
+\r
+import junit.framework.TestCase;\r
+\r
+public final class TestClean extends TestCase {\r
+\r
+ public void testClean() {\r
+ HSSFWorkbook wb = new HSSFWorkbook();\r
+ HSSFCell cell = wb.createSheet().createRow(0).createCell(0);\r
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);\r
+\r
+ String[] asserts = {\r
+ "aniket\u0007\u0017\u0019", "aniket",\r
+ "\u0011aniket\u0007\u0017\u0010", "aniket",\r
+ "\u0011aniket\u0007\u0017\u007F", "aniket\u007F",\r
+ "\u2116aniket\u2211\uFB5E\u2039", "\u2116aniket\u2211\uFB5E\u2039",\r
+ };\r
+\r
+ for(int i = 0; i < asserts.length; i+= 2){\r
+ String formulaText = "CLEAN(\"" + asserts[i] + "\")";\r
+ confirmResult(fe, cell, formulaText, asserts[i + 1]);\r
+ }\r
+\r
+ asserts = new String[] {\r
+ "CHAR(7)&\"text\"&CHAR(7)", "text",\r
+ "CHAR(7)&\"text\"&CHAR(17)", "text",\r
+ "CHAR(181)&\"text\"&CHAR(190)", "\u00B5text\u00BE",\r
+ "\"text\"&CHAR(160)&\"'\"", "text\u00A0'",\r
+ };\r
+ for(int i = 0; i < asserts.length; i+= 2){\r
+ String formulaText = "CLEAN(" + asserts[i] + ")";\r
+ confirmResult(fe, cell, formulaText, asserts[i + 1]);\r
+ }\r
+ }\r
+\r
+ private static void confirmResult(HSSFFormulaEvaluator fe, HSSFCell cell, String formulaText,\r
+ String expectedResult) {\r
+ cell.setCellFormula(formulaText);\r
+ fe.notifyUpdateCell(cell);\r
+ CellValue result = fe.evaluate(cell);\r
+ assertEquals(result.getCellType(), HSSFCell.CELL_TYPE_STRING);\r
+ assertEquals(expectedResult, result.getStringValue());\r
+ }\r
+}\r