aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPJ Fanning <fanningpj@apache.org>2017-07-03 20:56:02 +0000
committerPJ Fanning <fanningpj@apache.org>2017-07-03 20:56:02 +0000
commit26389768b9f43a04cb668fc3cac968a34aa814e8 (patch)
treebe460a3355e482dc0cb9b1dd217525f25370103c
parentc78f22564ff25ade38e42eb7523499fcc40a737c (diff)
downloadpoi-26389768b9f43a04cb668fc3cac968a34aa814e8.tar.gz
poi-26389768b9f43a04cb668fc3cac968a34aa814e8.zip
[Bug 60422] fix data formatter issue with specific format in German locale
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1800713 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--src/java/org/apache/poi/ss/format/CellDateFormatter.java14
-rw-r--r--src/java/org/apache/poi/ss/format/CellFormat.java69
-rw-r--r--src/java/org/apache/poi/ss/format/CellFormatPart.java17
-rw-r--r--src/java/org/apache/poi/ss/format/CellFormatType.java32
-rw-r--r--src/java/org/apache/poi/ss/format/CellFormatter.java15
-rw-r--r--src/java/org/apache/poi/ss/format/CellGeneralFormatter.java10
-rw-r--r--src/java/org/apache/poi/ss/format/CellNumberFormatter.java102
-rw-r--r--src/java/org/apache/poi/ss/usermodel/DataFormatter.java22
-rw-r--r--src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java21
9 files changed, 213 insertions, 89 deletions
diff --git a/src/java/org/apache/poi/ss/format/CellDateFormatter.java b/src/java/org/apache/poi/ss/format/CellDateFormatter.java
index 11c567c4c9..a59fd0c72b 100644
--- a/src/java/org/apache/poi/ss/format/CellDateFormatter.java
+++ b/src/java/org/apache/poi/ss/format/CellDateFormatter.java
@@ -138,6 +138,16 @@ public class CellDateFormatter extends CellFormatter {
* @param format The format.
*/
public CellDateFormatter(String format) {
+ this(LocaleUtil.getUserLocale(), format);
+ }
+
+ /**
+ * Creates a new date formatter with the given specification.
+ *
+ * @param locale The locale.
+ * @param format The format.
+ */
+ public CellDateFormatter(Locale locale, String format) {
super(format);
DatePartHandler partHandler = new DatePartHandler();
StringBuffer descBuf = CellFormatPart.parseFormat(format,
@@ -146,7 +156,7 @@ public class CellDateFormatter extends CellFormatter {
// tweak the format pattern to pass tests on JDK 1.7,
// See https://issues.apache.org/bugzilla/show_bug.cgi?id=53369
String ptrn = descBuf.toString().replaceAll("((y)(?!y))(?<!yy)", "yy");
- dateFmt = new SimpleDateFormat(ptrn, LocaleUtil.getUserLocale());
+ dateFmt = new SimpleDateFormat(ptrn, locale);
dateFmt.setTimeZone(LocaleUtil.getUserTimeZone());
}
@@ -182,7 +192,7 @@ public class CellDateFormatter extends CellFormatter {
Formatter formatter = new Formatter(toAppendTo, Locale.ROOT);
try {
long msecs = dateObj.getTime() % 1000;
- formatter.format(LocaleUtil.getUserLocale(), sFmt, msecs / 1000.0);
+ formatter.format(locale, sFmt, msecs / 1000.0);
} finally {
formatter.close();
}
diff --git a/src/java/org/apache/poi/ss/format/CellFormat.java b/src/java/org/apache/poi/ss/format/CellFormat.java
index bad8497126..415506b0d3 100644
--- a/src/java/org/apache/poi/ss/format/CellFormat.java
+++ b/src/java/org/apache/poi/ss/format/CellFormat.java
@@ -20,6 +20,7 @@ package org.apache.poi.ss.format;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.logging.Level;
@@ -35,6 +36,7 @@ import org.apache.poi.ss.usermodel.ConditionalFormattingRule;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.util.DateFormatConverter;
+import org.apache.poi.util.LocaleUtil;
/**
* Format a value according to the standard Excel behavior. This "standard" is
@@ -90,6 +92,7 @@ import org.apache.poi.ss.util.DateFormatConverter;
* native character numbers, as documented at https://help.libreoffice.org/Common/Number_Format_Codes
*/
public class CellFormat {
+ private final Locale locale;
private final String format;
private final CellFormatPart posNumFmt;
private final CellFormatPart zeroNumFmt;
@@ -101,9 +104,6 @@ public class CellFormat {
CellFormatPart.FORMAT_PAT.pattern() + "(;|$)",
Pattern.COMMENTS | Pattern.CASE_INSENSITIVE);
- private static final CellFormatPart DEFAULT_TEXT_FORMAT =
- new CellFormatPart("@");
-
/*
* Cells that cannot be formatted, e.g. cells that have a date or time
* format and have an invalid date or time value, are displayed as 255
@@ -121,18 +121,23 @@ public class CellFormat {
/**
* Format a value as it would be were no format specified. This is also
* used when the format specified is <tt>General</tt>.
+ * @deprecated use {@link #getInstance(Locale, "General")} instead
*/
- public static final CellFormat GENERAL_FORMAT = new CellFormat("General") {
- @Override
- public CellFormatResult apply(Object value) {
- String text = (new CellGeneralFormatter()).format(value);
- return new CellFormatResult(true, text, null);
- }
- };
+ public static final CellFormat GENERAL_FORMAT = createGeneralFormat(LocaleUtil.getUserLocale());
+
+ private static CellFormat createGeneralFormat(final Locale locale) {
+ return new CellFormat(locale, "General") {
+ @Override
+ public CellFormatResult apply(Object value) {
+ String text = (new CellGeneralFormatter(locale)).format(value);
+ return new CellFormatResult(true, text, null);
+ }
+ };
+ }
/** Maps a format string to its parsed version for efficiencies sake. */
- private static final Map<String, CellFormat> formatCache =
- new WeakHashMap<String, CellFormat>();
+ private static final Map<Locale, Map<String, CellFormat>> formatCache =
+ new WeakHashMap<Locale, Map<String, CellFormat>>();
/**
* Returns a {@link CellFormat} that applies the given format. Two calls
@@ -143,13 +148,31 @@ public class CellFormat {
* @return A {@link CellFormat} that applies the given format.
*/
public static CellFormat getInstance(String format) {
- CellFormat fmt = formatCache.get(format);
+ return getInstance(LocaleUtil.getUserLocale(), format);
+ }
+
+ /**
+ * Returns a {@link CellFormat} that applies the given format. Two calls
+ * with the same format may or may not return the same object.
+ *
+ * @param locale The locale.
+ * @param format The format.
+ *
+ * @return A {@link CellFormat} that applies the given format.
+ */
+ public static synchronized CellFormat getInstance(Locale locale, String format) {
+ Map<String, CellFormat> formatMap = formatCache.get(locale);
+ if (formatMap == null) {
+ formatMap = new WeakHashMap<String, CellFormat>();
+ formatCache.put(locale, formatMap);
+ }
+ CellFormat fmt = formatMap.get(format);
if (fmt == null) {
if (format.equals("General") || format.equals("@"))
- fmt = GENERAL_FORMAT;
+ fmt = createGeneralFormat(locale);
else
- fmt = new CellFormat(format);
- formatCache.put(format, fmt);
+ fmt = new CellFormat(locale, format);
+ formatMap.put(format, fmt);
}
return fmt;
}
@@ -159,8 +182,10 @@ public class CellFormat {
*
* @param format The format.
*/
- private CellFormat(String format) {
+ private CellFormat(Locale locale, String format) {
+ this.locale = locale;
this.format = format;
+ CellFormatPart defaultTextFormat = new CellFormatPart(locale, "@");
Matcher m = ONE_PART.matcher(format);
List<CellFormatPart> parts = new ArrayList<CellFormatPart>();
@@ -172,7 +197,7 @@ public class CellFormat {
if (valueDesc.endsWith(";"))
valueDesc = valueDesc.substring(0, valueDesc.length() - 1);
- parts.add(new CellFormatPart(valueDesc));
+ parts.add(new CellFormatPart(locale, valueDesc));
} catch (RuntimeException e) {
CellFormatter.logger.log(Level.WARNING,
"Invalid format: " + CellFormatter.quote(m.group()), e);
@@ -187,19 +212,19 @@ public class CellFormat {
posNumFmt = parts.get(0);
negNumFmt = null;
zeroNumFmt = null;
- textFmt = DEFAULT_TEXT_FORMAT;
+ textFmt = defaultTextFormat;
break;
case 2:
posNumFmt = parts.get(0);
negNumFmt = parts.get(1);
zeroNumFmt = null;
- textFmt = DEFAULT_TEXT_FORMAT;
+ textFmt = defaultTextFormat;
break;
case 3:
posNumFmt = parts.get(0);
negNumFmt = parts.get(1);
zeroNumFmt = parts.get(2);
- textFmt = DEFAULT_TEXT_FORMAT;
+ textFmt = defaultTextFormat;
break;
case 4:
default:
@@ -384,7 +409,7 @@ public class CellFormat {
|| (posNumFmt.hasCondition() && posNumFmt.applies(val))) {
return posNumFmt;
} else {
- return new CellFormatPart("General");
+ return new CellFormatPart(locale, "General");
}
} else if (formatPartCount == 2) {
if ((!posNumFmt.hasCondition() && val >= 0)
diff --git a/src/java/org/apache/poi/ss/format/CellFormatPart.java b/src/java/org/apache/poi/ss/format/CellFormatPart.java
index b4b508fb30..40cfb4a76e 100644
--- a/src/java/org/apache/poi/ss/format/CellFormatPart.java
+++ b/src/java/org/apache/poi/ss/format/CellFormatPart.java
@@ -17,6 +17,7 @@
package org.apache.poi.ss.format;
import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.util.LocaleUtil;
import javax.swing.*;
@@ -173,6 +174,16 @@ public class CellFormatPart {
* @param desc The string to parse.
*/
public CellFormatPart(String desc) {
+ this(LocaleUtil.getUserLocale(), desc);
+ }
+
+ /**
+ * Create an object to represent a format part.
+ *
+ * @param locale The locale to use.
+ * @param desc The string to parse.
+ */
+ public CellFormatPart(Locale locale, String desc) {
Matcher m = FORMAT_PAT.matcher(desc);
if (!m.matches()) {
throw new IllegalArgumentException("Unrecognized format: " + quote(
@@ -181,7 +192,7 @@ public class CellFormatPart {
color = getColor(m);
condition = getCondition(m);
type = getCellFormatType(m);
- format = getFormatter(m);
+ format = getFormatter(locale, m);
}
/**
@@ -287,7 +298,7 @@ public class CellFormatPart {
*
* @return The formatter.
*/
- private CellFormatter getFormatter(Matcher matcher) {
+ private CellFormatter getFormatter(Locale locale, Matcher matcher) {
String fdesc = matcher.group(SPECIFICATION_GROUP);
// For now, we don't support localised currencies, so simplify if there
@@ -305,7 +316,7 @@ public class CellFormatPart {
}
// Build a formatter for this simplified string
- return type.formatter(fdesc);
+ return type.formatter(locale, fdesc);
}
/**
diff --git a/src/java/org/apache/poi/ss/format/CellFormatType.java b/src/java/org/apache/poi/ss/format/CellFormatType.java
index e1f436bdc8..af947b1db4 100644
--- a/src/java/org/apache/poi/ss/format/CellFormatType.java
+++ b/src/java/org/apache/poi/ss/format/CellFormatType.java
@@ -17,6 +17,8 @@
package org.apache.poi.ss.format;
+import java.util.Locale;
+
/**
* The different kinds of formats that the formatter understands.
*
@@ -26,11 +28,14 @@ public enum CellFormatType {
/** The general (default) format; also used for <tt>"General"</tt>. */
GENERAL {
+ boolean isSpecial(char ch) {
+ return false;
+ }
CellFormatter formatter(String pattern) {
return new CellGeneralFormatter();
}
- boolean isSpecial(char ch) {
- return false;
+ CellFormatter formatter(Locale locale, String pattern) {
+ return new CellGeneralFormatter(locale);
}
},
/** A numeric format. */
@@ -41,6 +46,9 @@ public enum CellFormatType {
CellFormatter formatter(String pattern) {
return new CellNumberFormatter(pattern);
}
+ CellFormatter formatter(Locale locale, String pattern) {
+ return new CellNumberFormatter(locale, pattern);
+ }
},
/** A date format. */
DATE {
@@ -50,6 +58,9 @@ public enum CellFormatType {
CellFormatter formatter(String pattern) {
return new CellDateFormatter(pattern);
}
+ CellFormatter formatter(Locale locale, String pattern) {
+ return new CellDateFormatter(locale, pattern);
+ }
},
/** An elapsed time format. */
ELAPSED {
@@ -59,6 +70,9 @@ public enum CellFormatType {
CellFormatter formatter(String pattern) {
return new CellElapsedFormatter(pattern);
}
+ CellFormatter formatter(Locale locale, String pattern) {
+ return new CellElapsedFormatter(pattern);
+ }
},
/** A text format. */
TEXT {
@@ -68,6 +82,9 @@ public enum CellFormatType {
CellFormatter formatter(String pattern) {
return new CellTextFormatter(pattern);
}
+ CellFormatter formatter(Locale locale, String pattern) {
+ return new CellTextFormatter(pattern);
+ }
};
/**
@@ -88,4 +105,15 @@ public enum CellFormatType {
* @return A new formatter of the appropriate type, for the given pattern.
*/
abstract CellFormatter formatter(String pattern);
+
+ /**
+ * Returns a new formatter of the appropriate type, for the given pattern.
+ * The pattern must be appropriate for the type.
+ *
+ * @param locale The locale to use.
+ * @param pattern The pattern to use.
+ *
+ * @return A new formatter of the appropriate type, for the given pattern.
+ */
+ abstract CellFormatter formatter(Locale locale, String pattern);
}
diff --git a/src/java/org/apache/poi/ss/format/CellFormatter.java b/src/java/org/apache/poi/ss/format/CellFormatter.java
index e529a90f16..2803c37e59 100644
--- a/src/java/org/apache/poi/ss/format/CellFormatter.java
+++ b/src/java/org/apache/poi/ss/format/CellFormatter.java
@@ -16,8 +16,11 @@
==================================================================== */
package org.apache.poi.ss.format;
+import java.util.Locale;
import java.util.logging.Logger;
+import org.apache.poi.util.LocaleUtil;
+
/**
* This is the abstract supertype for the various cell formatters.
*
@@ -26,6 +29,7 @@ import java.util.logging.Logger;
public abstract class CellFormatter {
/** The original specified format. */
protected final String format;
+ protected final Locale locale;
/**
* Creates a new formatter object, storing the format in {@link #format}.
@@ -33,6 +37,17 @@ public abstract class CellFormatter {
* @param format The format.
*/
public CellFormatter(String format) {
+ this(LocaleUtil.getUserLocale(), format);
+ }
+
+ /**
+ * Creates a new formatter object, storing the format in {@link #format}.
+ *
+ * @param locale The locale.
+ * @param format The format.
+ */
+ public CellFormatter(Locale locale, String format) {
+ this.locale = locale;
this.format = format;
}
diff --git a/src/java/org/apache/poi/ss/format/CellGeneralFormatter.java b/src/java/org/apache/poi/ss/format/CellGeneralFormatter.java
index 52df33b72c..37f202c9dd 100644
--- a/src/java/org/apache/poi/ss/format/CellGeneralFormatter.java
+++ b/src/java/org/apache/poi/ss/format/CellGeneralFormatter.java
@@ -29,7 +29,11 @@ import org.apache.poi.util.LocaleUtil;
public class CellGeneralFormatter extends CellFormatter {
/** Creates a new general formatter. */
public CellGeneralFormatter() {
- super("General");
+ this(LocaleUtil.getUserLocale());
+ }
+ /** Creates a new general formatter. */
+ public CellGeneralFormatter(Locale locale) {
+ super(locale, "General");
}
/**
@@ -59,9 +63,9 @@ public class CellGeneralFormatter extends CellFormatter {
stripZeros = false;
}
- Formatter formatter = new Formatter(toAppendTo, LocaleUtil.getUserLocale());
+ Formatter formatter = new Formatter(toAppendTo, locale);
try {
- formatter.format(LocaleUtil.getUserLocale(), fmt, value);
+ formatter.format(locale, fmt, value);
} finally {
formatter.close();
}
diff --git a/src/java/org/apache/poi/ss/format/CellNumberFormatter.java b/src/java/org/apache/poi/ss/format/CellNumberFormatter.java
index 668149f85a..9657572e40 100644
--- a/src/java/org/apache/poi/ss/format/CellNumberFormatter.java
+++ b/src/java/org/apache/poi/ss/format/CellNumberFormatter.java
@@ -26,6 +26,7 @@ import java.util.Formatter;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
+import java.util.Locale;
import java.util.Set;
import java.util.TreeSet;
@@ -48,7 +49,7 @@ public class CellNumberFormatter extends CellFormatter {
private final Special numerator;
private final Special afterInteger;
private final Special afterFractional;
- private final boolean integerCommas;
+ private final boolean showGroupingSeparator;
private final List<Special> specials = new ArrayList<Special>();
private final List<Special> integerSpecials = new ArrayList<Special>();
private final List<Special> fractionalSpecials = new ArrayList<Special>();
@@ -69,13 +70,11 @@ public class CellNumberFormatter extends CellFormatter {
// ("#" for integer values, and "#.#" for floating-point values) is
// different from the 'General' format for numbers ("#" for integer
// values and "#.#########" for floating-point values).
- private static final CellFormatter SIMPLE_NUMBER = new GeneralNumberFormatter();
- private static final CellFormatter SIMPLE_INT = new CellNumberFormatter("#");
- private static final CellFormatter SIMPLE_FLOAT = new CellNumberFormatter("#.#");
+ private final CellFormatter SIMPLE_NUMBER = new GeneralNumberFormatter(locale);
private static class GeneralNumberFormatter extends CellFormatter {
- private GeneralNumberFormatter() {
- super("General");
+ private GeneralNumberFormatter(Locale locale) {
+ super(locale, "General");
}
public void formatValue(StringBuffer toAppendTo, Object value) {
@@ -86,7 +85,8 @@ public class CellNumberFormatter extends CellFormatter {
CellFormatter cf;
if (value instanceof Number) {
Number num = (Number) value;
- cf = (num.doubleValue() % 1.0 == 0) ? SIMPLE_INT : SIMPLE_FLOAT;
+ cf = (num.doubleValue() % 1.0 == 0) ? new CellNumberFormatter(locale, "#") :
+ new CellNumberFormatter(locale, "#.#");
} else {
cf = CellTextFormatter.SIMPLE_TEXT;
}
@@ -124,7 +124,17 @@ public class CellNumberFormatter extends CellFormatter {
* @param format The format to parse.
*/
public CellNumberFormatter(String format) {
- super(format);
+ this(LocaleUtil.getUserLocale(), format);
+ }
+
+ /**
+ * Creates a new cell number formatter.
+ *
+ * @param locale The locale to use.
+ * @param format The format to parse.
+ */
+ public CellNumberFormatter(Locale locale, String format) {
+ super(locale, format);
CellNumberPartHandler ph = new CellNumberPartHandler();
StringBuffer descBuf = CellFormatPart.parseFormat(format, CellFormatType.NUMBER, ph);
@@ -177,7 +187,7 @@ public class CellNumberFormatter extends CellFormatter {
}
double scaleByRef[] = { ph.getScale() };
- integerCommas = interpretIntegerCommas(descBuf, specials, decimalPoint, integerEnd(), fractionalEnd(), scaleByRef);
+ showGroupingSeparator = interpretIntegerCommas(descBuf, specials, decimalPoint, integerEnd(), fractionalEnd(), scaleByRef);
if (exponent == null) {
scale = scaleByRef[0];
} else {
@@ -259,14 +269,17 @@ public class CellNumberFormatter extends CellFormatter {
}
fmtBuf.append('E');
placeZeros(fmtBuf, exponentSpecials.subList(2, exponentSpecials.size()));
- DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(LocaleUtil.getUserLocale());
- decimalFmt = new DecimalFormat(fmtBuf.toString(), dfs);
+ decimalFmt = new DecimalFormat(fmtBuf.toString(), getDecimalFormatSymbols());
printfFmt = null;
}
desc = descBuf.toString();
}
+ private DecimalFormatSymbols getDecimalFormatSymbols() {
+ return DecimalFormatSymbols.getInstance(locale);
+ }
+
private static void placeZeros(StringBuffer sb, List<Special> specials) {
for (Special s : specials) {
if (isDigitFmt(s)) {
@@ -436,7 +449,7 @@ public class CellNumberFormatter extends CellFormatter {
}
Set<CellNumberStringMod> mods = new TreeSet<CellNumberStringMod>();
- StringBuffer output = new StringBuffer(desc);
+ StringBuffer output = new StringBuffer(localiseFormat(desc));
if (exponent != null) {
writeScientific(value, output, mods);
@@ -444,21 +457,24 @@ public class CellNumberFormatter extends CellFormatter {
writeFraction(value, null, fractional, output, mods);
} else {
StringBuffer result = new StringBuffer();
- Formatter f = new Formatter(result, LocaleUtil.getUserLocale());
+ Formatter f = new Formatter(result, locale);
try {
- f.format(LocaleUtil.getUserLocale(), printfFmt, value);
+ f.format(locale, printfFmt, value);
} finally {
f.close();
}
if (numerator == null) {
writeFractional(result, output);
- writeInteger(result, output, integerSpecials, mods, integerCommas);
+ writeInteger(result, output, integerSpecials, mods, showGroupingSeparator);
} else {
writeFraction(value, result, fractional, output, mods);
}
}
+ DecimalFormatSymbols dfs = getDecimalFormatSymbols();
+ String groupingSeparator = Character.toString(dfs.getGroupingSeparator());
+
// Now strip out any remaining '#'s and add any pending text ...
Iterator<CellNumberStringMod> changes = mods.iterator();
CellNumberStringMod nextChange = (changes.hasNext() ? changes.next() : null);
@@ -478,7 +494,7 @@ public class CellNumberFormatter extends CellFormatter {
switch (nextChange.getOp()) {
case CellNumberStringMod.AFTER:
// ignore adding a comma after a deleted char (which was a '#')
- if (nextChange.getToAdd().equals(",") && deletedChars.get(s.pos)) {
+ if (nextChange.getToAdd().equals(groupingSeparator) && deletedChars.get(s.pos)) {
break;
}
output.insert(modPos + 1, nextChange.getToAdd());
@@ -545,7 +561,7 @@ public class CellNumberFormatter extends CellFormatter {
StringBuffer result = new StringBuffer();
FieldPosition fractionPos = new FieldPosition(DecimalFormat.FRACTION_FIELD);
decimalFmt.format(value, result, fractionPos);
- writeInteger(result, output, integerSpecials, mods, integerCommas);
+ writeInteger(result, output, integerSpecials, mods, showGroupingSeparator);
writeFractional(result, output);
/*
@@ -683,6 +699,27 @@ public class CellNumberFormatter extends CellFormatter {
LOG.log(POILogger.ERROR, "error while fraction evaluation", ignored);
}
}
+
+ private String localiseFormat(String format) {
+ DecimalFormatSymbols dfs = getDecimalFormatSymbols();
+ if(format.contains(",") && dfs.getGroupingSeparator() != ',') {
+ if(format.contains(".") && dfs.getDecimalSeparator() != '.') {
+ format = replaceLast(format, "\\.", "[DECIMAL_SEPARATOR]");
+ format = format.replace(',', dfs.getGroupingSeparator())
+ .replace("[DECIMAL_SEPARATOR]", Character.toString(dfs.getDecimalSeparator()));
+ } else {
+ format = format.replace(',', dfs.getGroupingSeparator());
+ }
+ } else if(format.contains(".") && dfs.getDecimalSeparator() != '.') {
+ format = format.replace('.', dfs.getDecimalSeparator());
+ }
+ return format;
+ }
+
+
+ private static String replaceLast(String text, String regex, String replacement) {
+ return text.replaceFirst("(?s)(.*)" + regex, "$1" + replacement);
+ }
private static boolean hasChar(char ch, List<Special>... numSpecials) {
for (List<Special> specials : numSpecials) {
@@ -698,9 +735,9 @@ public class CellNumberFormatter extends CellFormatter {
private void writeSingleInteger(String fmt, int num, StringBuffer output, List<Special> numSpecials, Set<CellNumberStringMod> mods) {
StringBuffer sb = new StringBuffer();
- Formatter formatter = new Formatter(sb, LocaleUtil.getUserLocale());
+ Formatter formatter = new Formatter(sb, locale);
try {
- formatter.format(LocaleUtil.getUserLocale(), fmt, num);
+ formatter.format(locale, fmt, num);
} finally {
formatter.close();
}
@@ -709,9 +746,13 @@ public class CellNumberFormatter extends CellFormatter {
private void writeInteger(StringBuffer result, StringBuffer output,
List<Special> numSpecials, Set<CellNumberStringMod> mods,
- boolean showCommas) {
+ boolean showGroupingSeparator) {
+
+ DecimalFormatSymbols dfs = getDecimalFormatSymbols();
+ String decimalSeparator = Character.toString(dfs.getDecimalSeparator());
+ String groupingSeparator = Character.toString(dfs.getGroupingSeparator());
- int pos = result.indexOf(".") - 1;
+ int pos = result.indexOf(decimalSeparator) - 1;
if (pos < 0) {
if (exponent != null && numSpecials == integerSpecials) {
pos = result.indexOf("E") - 1;
@@ -723,13 +764,13 @@ public class CellNumberFormatter extends CellFormatter {
int strip;
for (strip = 0; strip < pos; strip++) {
char resultCh = result.charAt(strip);
- if (resultCh != '0' && resultCh != ',') {
+ if (resultCh != '0' && resultCh != dfs.getGroupingSeparator()) {
break;
}
}
ListIterator<Special> it = numSpecials.listIterator(numSpecials.size());
- boolean followWithComma = false;
+ boolean followWithGroupingSeparator = false;
Special lastOutputIntegerDigit = null;
int digit = 0;
while (it.hasPrevious()) {
@@ -741,16 +782,16 @@ public class CellNumberFormatter extends CellFormatter {
resultCh = '0';
}
Special s = it.previous();
- followWithComma = showCommas && digit > 0 && digit % 3 == 0;
+ followWithGroupingSeparator = showGroupingSeparator && digit > 0 && digit % 3 == 0;
boolean zeroStrip = false;
if (resultCh != '0' || s.ch == '0' || s.ch == '?' || pos >= strip) {
zeroStrip = s.ch == '?' && pos < strip;
output.setCharAt(s.pos, (zeroStrip ? ' ' : resultCh));
lastOutputIntegerDigit = s;
}
- if (followWithComma) {
- mods.add(insertMod(s, zeroStrip ? " " : ",", CellNumberStringMod.AFTER));
- followWithComma = false;
+ if (followWithGroupingSeparator) {
+ mods.add(insertMod(s, zeroStrip ? " " : groupingSeparator, CellNumberStringMod.AFTER));
+ followWithGroupingSeparator = false;
}
digit++;
--pos;
@@ -761,10 +802,10 @@ public class CellNumberFormatter extends CellFormatter {
// pos was decremented at the end of the loop above when the iterator was at its end
++pos;
extraLeadingDigits = new StringBuffer(result.substring(0, pos));
- if (showCommas) {
+ if (showGroupingSeparator) {
while (pos > 0) {
if (digit > 0 && digit % 3 == 0) {
- extraLeadingDigits.insert(pos, ',');
+ extraLeadingDigits.insert(pos, groupingSeparator);
}
digit++;
--pos;
@@ -778,7 +819,8 @@ public class CellNumberFormatter extends CellFormatter {
int digit;
int strip;
if (fractionalSpecials.size() > 0) {
- digit = result.indexOf(".") + 1;
+ String decimalSeparator = Character.toString(getDecimalFormatSymbols().getDecimalSeparator());
+ digit = result.indexOf(decimalSeparator) + 1;
if (exponent != null) {
strip = result.indexOf("e") - 1;
} else {
diff --git a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java
index f07225432c..0da7b6e714 100644
--- a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java
+++ b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java
@@ -292,10 +292,6 @@ public class DataFormatter implements Observer {
* @param cell The cell to retrieve a Format for
* @return A Format for the format String
*/
- private Format getFormat(Cell cell) {
- return getFormat(cell, null);
- }
-
private Format getFormat(Cell cell, ConditionalFormattingEvaluator cfEvaluator) {
if (cell == null) return null;
@@ -315,12 +311,12 @@ public class DataFormatter implements Observer {
private Format getFormat(double cellValue, int formatIndex, String formatStrIn) {
localeChangedObservable.checkForLocaleChange();
-
-// // Might be better to separate out the n p and z formats, falling back to p when n and z are not set.
-// // That however would require other code to be re factored.
-// String[] formatBits = formatStrIn.split(";");
-// int i = cellValue > 0.0 ? 0 : cellValue < 0.0 ? 1 : 2;
-// String formatStr = (i < formatBits.length) ? formatBits[i] : formatBits[0];
+
+ // Might be better to separate out the n p and z formats, falling back to p when n and z are not set.
+ // That however would require other code to be re factored.
+ // String[] formatBits = formatStrIn.split(";");
+ // int i = cellValue > 0.0 ? 0 : cellValue < 0.0 ? 1 : 2;
+ // String formatStr = (i < formatBits.length) ? formatBits[i] : formatBits[0];
String formatStr = formatStrIn;
@@ -336,7 +332,7 @@ public class DataFormatter implements Observer {
) ) {
try {
// Ask CellFormat to get a formatter for it
- CellFormat cfmt = CellFormat.getInstance(formatStr);
+ CellFormat cfmt = CellFormat.getInstance(locale, formatStr);
// CellFormat requires callers to identify date vs not, so do so
Object cellValueO = Double.valueOf(cellValue);
if (DateUtil.isADateFormat(formatIndex, formatStr) &&
@@ -607,7 +603,7 @@ public class DataFormatter implements Observer {
try {
return new ExcelStyleDateFormatter(formatStr, dateSymbols);
} catch(IllegalArgumentException iae) {
-
+ logger.log(POILogger.DEBUG, "Formatting failed for format " + formatStr + ", falling back", iae);
// the pattern could not be parsed correctly,
// so fall back to the default number format
return getDefaultFormat(cellValue);
@@ -718,7 +714,7 @@ public class DataFormatter implements Observer {
setExcelStyleRoundingMode(df);
return df;
} catch(IllegalArgumentException iae) {
-
+ logger.log(POILogger.DEBUG, "Formatting failed for format " + formatStr + ", falling back", iae);
// the pattern could not be parsed correctly,
// so fall back to the default number format
return getDefaultFormat(cellValue);
diff --git a/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java b/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java
index 679404f141..211f801913 100644
--- a/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java
+++ b/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java
@@ -811,7 +811,6 @@ public class TestDataFormatter {
CellReference ref = new CellReference("D47");
Cell cell = wb.getSheetAt(0).getRow(ref.getRow()).getCell(ref.getCol());
- //noinspection deprecation
assertEquals(CellType.FORMULA, cell.getCellTypeEnum());
assertEquals("G9:K9 I7:I12", cell.getCellFormula());
@@ -888,18 +887,12 @@ public class TestDataFormatter {
≈ */
@Test
public void testBug60422() {
- //when this is set to Locale.Germany, the result is
- LocaleUtil.setUserLocale(Locale.ROOT);
- try {
- char euro = '\u20AC';
- DataFormatter df = new DataFormatter(Locale.GERMANY);
- String formatString = String.format(Locale.ROOT,
- "_-* #,##0.00\\ \"%s\"_-;\\-* #,##0.00\\ \"%s\"_-;_-* \"-\"??\\ \"%s\"_-;_-@_-",
- euro, euro, euro);
- //this should be 4,33
- assertEquals("4.33 " + euro, df.formatRawCellContents(4.33, 178, formatString));
- } finally {
- LocaleUtil.resetUserLocale();
- }
+ char euro = '\u20AC';
+ DataFormatter df = new DataFormatter(Locale.GERMANY);
+ String formatString = String.format(Locale.ROOT,
+ "_-* #,##0.00\\ \"%s\"_-;\\-* #,##0.00\\ \"%s\"_-;_-* \"-\"??\\ \"%s\"_-;_-@_-",
+ euro, euro, euro);
+ assertEquals("4,33 " + euro, df.formatRawCellContents(4.33, 178, formatString));
+ assertEquals("1.234,33 " + euro, df.formatRawCellContents(1234.33, 178, formatString));
}
}