From 726dc7a5783f87a725b599bd55bc5b59df72675f Mon Sep 17 00:00:00 2001 From: Dominik Stadler Date: Fri, 15 Jul 2016 06:32:45 +0000 Subject: [PATCH] Function PROPER: Don't use a regular expression syntax that is not available on Android. Actually the use of regular expression in this case was overkill, slow and even incorrect in corner cases, the function can be done without regex easily and runs a bit faster anyway (microBench is down from 4sec to 2s) Also added a unit-test to ensure the behavior stays the same (except in cases where it needed fixing, e.g. some toUppercase() leads to more than one character which was handled incorrectly) git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1752779 13f79535-47bb-0310-9956-ffa450edef68 --- .../ss/formula/functions/TextFunction.java | 41 +++++------- .../poi/ss/formula/functions/TestProper.java | 62 +++++++++++++++++++ 2 files changed, 79 insertions(+), 24 deletions(-) create mode 100644 src/testcases/org/apache/poi/ss/formula/functions/TestProper.java 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 3c08eee787..82082bb9c3 100644 --- a/src/java/org/apache/poi/ss/formula/functions/TextFunction.java +++ b/src/java/org/apache/poi/ss/formula/functions/TextFunction.java @@ -17,18 +17,11 @@ package org.apache.poi.ss.formula.functions; -import java.util.Locale; -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; -import org.apache.poi.ss.formula.eval.NumberEval; -import org.apache.poi.ss.formula.eval.OperandResolver; -import org.apache.poi.ss.formula.eval.StringEval; -import org.apache.poi.ss.formula.eval.ValueEval; +import org.apache.poi.ss.formula.eval.*; import org.apache.poi.ss.usermodel.DataFormatter; +import java.util.Locale; + /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * @author Josh Micich @@ -36,18 +29,17 @@ import org.apache.poi.ss.usermodel.DataFormatter; */ public abstract class TextFunction implements Function { protected static final DataFormatter formatter = new DataFormatter(); - protected static final String EMPTY_STRING = ""; - protected static final String evaluateStringArg(ValueEval eval, int srcRow, int srcCol) throws EvaluationException { + protected static String evaluateStringArg(ValueEval eval, int srcRow, int srcCol) throws EvaluationException { ValueEval ve = OperandResolver.getSingleValue(eval, srcRow, srcCol); return OperandResolver.coerceValueToString(ve); } - protected static final int evaluateIntArg(ValueEval arg, int srcCellRow, int srcCellCol) throws EvaluationException { + protected static int evaluateIntArg(ValueEval arg, int srcCellRow, int srcCellCol) throws EvaluationException { ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol); return OperandResolver.coerceValueToInt(ve); } - protected static final double evaluateDoubleArg(ValueEval arg, int srcCellRow, int srcCellCol) throws EvaluationException { + protected static double evaluateDoubleArg(ValueEval arg, int srcCellRow, int srcCellCol) throws EvaluationException { ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol); return OperandResolver.coerceValueToDouble(ve); } @@ -122,21 +114,23 @@ public abstract class TextFunction implements Function { * 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; - final String lowercaseText = text.toLowerCase(Locale.ROOT); - final String uppercaseText = text.toUpperCase(Locale.ROOT); final int length = text.length(); for(int i = 0; i < length; ++i) { + final char ch = text.charAt(i); + + // Note: we are using String.toUpperCase() here on purpose as it handles certain things + // better than Character.toUpperCase(), e.g. German "scharfes s" is translated + // to "SS" (i.e. two characters), if upercased properly! if (shouldMakeUppercase) { - sb.append(uppercaseText.charAt(i)); + sb.append(String.valueOf(ch).toUpperCase(Locale.ROOT)); } else { - sb.append(lowercaseText.charAt(i)); + sb.append(String.valueOf(ch).toLowerCase(Locale.ROOT)); } - shouldMakeUppercase = nonAlphabeticPattern.matcher(text.subSequence(i, i + 1)).matches(); + shouldMakeUppercase = !Character.isLetter(ch); } return new StringEval(sb.toString()); } @@ -184,8 +178,7 @@ public abstract class TextFunction implements Function { * @return whether the character is printable */ private boolean isPrintable(char c){ - int charCode = c; - return charCode >= 32; + return (int) c >= 32; } }; @@ -274,9 +267,9 @@ public abstract class TextFunction implements Function { public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) { StringBuilder sb = new StringBuilder(); - for (int i=0, iSize=args.length; i