]> source.dussan.org Git - poi.git/commitdiff
added implementations for CLEAN(), CHAR() and ADDRESS(), see Bugzilla 50607
authorYegor Kozlov <yegor@apache.org>
Wed, 19 Jan 2011 12:30:18 +0000 (12:30 +0000)
committerYegor Kozlov <yegor@apache.org>
Wed, 19 Jan 2011 12:30:18 +0000 (12:30 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1060788 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/ss/formula/eval/FunctionEval.java
src/java/org/apache/poi/ss/formula/functions/Address.java [new file with mode: 0644]
src/java/org/apache/poi/ss/formula/functions/TextFunction.java
src/testcases/org/apache/poi/ss/formula/functions/AllIndividualFunctionEvaluationTests.java
src/testcases/org/apache/poi/ss/formula/functions/TestAddress.java [new file with mode: 0644]
src/testcases/org/apache/poi/ss/formula/functions/TestClean.java [new file with mode: 0644]

index 591696ece1958b2fad2b81ecfb7b8151fd23ebb7..202938cffdf0063d2d511cc1ae8f7dfa1ddc0bf1 100644 (file)
@@ -34,6 +34,7 @@
 
     <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>
index a7bc15cee659aee4946ead1b0d043007c908ab7f..7c84a5860bdedb373d253309d2c8ff8ca96d0ce0 100644 (file)
@@ -130,6 +130,7 @@ public final class FunctionEval {
 
                retval[109] = NumericFunction.LOG;
 
+        retval[111] = TextFunction.CHAR;
                retval[112] = TextFunction.LOWER;
                retval[113] = TextFunction.UPPER;
 
@@ -148,7 +149,7 @@ public final class FunctionEval {
                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;
@@ -161,7 +162,7 @@ public final class FunctionEval {
 
                retval[212] = NumericFunction.ROUNDUP;
                retval[213] = NumericFunction.ROUNDDOWN;
-
+        retval[219] = new Address();  //Aniket Banerjee
         retval[220] = new Days360();
                retval[221] = new Today();
 
diff --git a/src/java/org/apache/poi/ss/formula/functions/Address.java b/src/java/org/apache/poi/ss/formula/functions/Address.java
new file mode 100644 (file)
index 0000000..288a88e
--- /dev/null
@@ -0,0 +1,103 @@
+/* ====================================================================\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
index dc57b4277b24080ac8d5d6583ee504cccc2de607..86e1e32687fef7a54a8611cc9b3e9ce83c40000a 100644 (file)
@@ -83,6 +83,25 @@ public abstract class TextFunction implements Function {
                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());
@@ -109,8 +128,43 @@ public abstract class TextFunction implements Function {
                        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/>
index 4e42389ec17fa9182fc343bb493be83d22f2ba0e..05c8a9bbd6f2520ed49de45030376fd2ac4ff4a7 100644 (file)
@@ -60,6 +60,8 @@ public final class AllIndividualFunctionEvaluationTests {
                result.addTestSuite(TestTrunc.class);
                result.addTestSuite(TestValue.class);
                result.addTestSuite(TestXYNumericFunction.class);
+               result.addTestSuite(TestAddress.class);
+               result.addTestSuite(TestClean.class);
                return result;
        }
 }
diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestAddress.java b/src/testcases/org/apache/poi/ss/formula/functions/TestAddress.java
new file mode 100644 (file)
index 0000000..ba25c4d
--- /dev/null
@@ -0,0 +1,76 @@
+/* ====================================================================\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
diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestClean.java b/src/testcases/org/apache/poi/ss/formula/functions/TestClean.java
new file mode 100644 (file)
index 0000000..ad717b1
--- /dev/null
@@ -0,0 +1,65 @@
+/* ====================================================================\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