From 5706aab18cec2cff1f8e4e06fbfbcc8a011beec8 Mon Sep 17 00:00:00 2001 From: Dominik Stadler Date: Mon, 20 Oct 2014 19:57:11 +0000 Subject: [PATCH] Bug 57010: Add implementation of function PROPER git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1633215 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/ss/formula/eval/FunctionEval.java | 2 +- .../ss/formula/functions/TextFunction.java | 28 ++++++ .../poi/ss/formula/functions/TestProper.java | 86 +++++++++++++++++++ 3 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/testcases/org/apache/poi/ss/formula/functions/TestProper.java diff --git a/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java b/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java index e828aad94..2809ee63f 100644 --- a/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java +++ b/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java @@ -207,7 +207,7 @@ public final class FunctionEval { retval[111] = TextFunction.CHAR; retval[112] = TextFunction.LOWER; retval[113] = TextFunction.UPPER; - + retval[114] = TextFunction.PROPER; retval[115] = TextFunction.LEFT; retval[116] = TextFunction.RIGHT; retval[117] = TextFunction.EXACT; diff --git a/src/java/org/apache/poi/ss/formula/functions/TextFunction.java b/src/java/org/apache/poi/ss/formula/functions/TextFunction.java index 1125ae55a..c09df12d1 100644 --- a/src/java/org/apache/poi/ss/formula/functions/TextFunction.java +++ b/src/java/org/apache/poi/ss/formula/functions/TextFunction.java @@ -17,6 +17,8 @@ package org.apache.poi.ss.formula.functions; +import java.util.regex.Pattern; + import org.apache.poi.ss.formula.eval.BoolEval; import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.formula.eval.EvaluationException; @@ -112,6 +114,32 @@ public abstract class TextFunction implements Function { return new StringEval(arg.toUpperCase()); } }; + + /** + * Implementation of the PROPER function: + * Normalizes all words (separated by non-word characters) by + * making the first letter upper and the rest lower case. + */ + public static final Function PROPER = new SingleArgTextFunc() { + final Pattern nonAlphabeticPattern = Pattern.compile("\\P{IsL}"); + protected ValueEval evaluate(String text) { + StringBuilder sb = new StringBuilder(); + boolean shouldMakeUppercase = true; + String lowercaseText = text.toLowerCase(); + String uppercaseText = text.toUpperCase(); + for(int i = 0; i < text.length(); ++i) { + if (shouldMakeUppercase) { + sb.append(uppercaseText.charAt(i)); + } + else { + sb.append(lowercaseText.charAt(i)); + } + shouldMakeUppercase = nonAlphabeticPattern.matcher(text.subSequence(i, i + 1)).matches(); + } + return new StringEval(sb.toString()); + } + }; + /** * An implementation of the TRIM function: * Removes leading and trailing spaces from value if evaluated operand diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestProper.java b/src/testcases/org/apache/poi/ss/formula/functions/TestProper.java new file mode 100644 index 000000000..6e98cfae4 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestProper.java @@ -0,0 +1,86 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.ss.formula.functions; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellValue; +import org.apache.poi.ss.usermodel.FormulaEvaluator; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +public final class TestProper extends TestCase { + private Cell cell11; + private FormulaEvaluator evaluator; + + public void testValidHSSF() { + HSSFWorkbook wb = new HSSFWorkbook(); + evaluator = new HSSFFormulaEvaluator(wb); + + confirm(wb); + } + + public void testValidXSSF() { + XSSFWorkbook wb = new XSSFWorkbook(); + evaluator = new XSSFFormulaEvaluator(wb); + + confirm(wb); + } + + private void confirm(Workbook wb) { + Sheet sheet = wb.createSheet("new sheet"); + cell11 = sheet.createRow(0).createCell(0); + cell11.setCellType(XSSFCell.CELL_TYPE_FORMULA); + + confirm("PROPER(\"hi there\")", "Hi There"); + confirm("PROPER(\"what's up\")", "What'S Up"); + confirm("PROPER(\"I DON'T TH!NK SO!\")", "I Don'T Th!Nk So!"); + confirm("PROPER(\"drÜbö'ä éloş|ëè \")", "Drübö'Ä Éloş|Ëè "); + confirm("PROPER(\"hi123 the123re\")", "Hi123 The123Re"); + confirm("PROPER(\"-\")", "-"); + confirm("PROPER(\"!§$\")", "!§$"); + confirm("PROPER(\"/&%\")", "/&%"); + + // also test longer string + StringBuilder builder = new StringBuilder("A"); + StringBuilder expected = new StringBuilder("A"); + for(int i = 1;i < 254;i++) { + builder.append((char)(65 + (i % 26))); + expected.append((char)(97 + (i % 26))); + } + confirm("PROPER(\"" + builder.toString() + "\")", expected.toString()); + } + + private void confirm(String formulaText, String expectedResult) { + cell11.setCellFormula(formulaText); + evaluator.clearAllCachedResultValues(); + CellValue cv = evaluator.evaluate(cell11); + if (cv.getCellType() != Cell.CELL_TYPE_STRING) { + throw new AssertionFailedError("Wrong result type: " + cv.formatAsString()); + } + String actualValue = cv.getStringValue(); + assertEquals(expectedResult, actualValue); + } +}