More fixes inspired by bug #48872 - handle zero formatting rules, and better color detection in DataFormatter
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@950035 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
ee9210d27b
commit
b303c57d54
@ -34,6 +34,8 @@
|
|||||||
|
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.7-SNAPSHOT" date="2010-??-??">
|
<release version="3.7-SNAPSHOT" date="2010-??-??">
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">48872 - handle zero formatting rules, and better color detection in DataFormatter</action>
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">48872 - support for more kinds of formatting in DataFormatter</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">43161 - fixed construction of the DIB picture header</action>
|
<action dev="POI-DEVELOPERS" type="fix">43161 - fixed construction of the DIB picture header</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">49311 - initial support for reading AES-encrypted/write-protected OOXML files</action>
|
<action dev="POI-DEVELOPERS" type="add">49311 - initial support for reading AES-encrypted/write-protected OOXML files</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">48718 - Make the creation of multiple, un-modified fonts in a row in XSSF match the old HSSF behaviour</action>
|
<action dev="POI-DEVELOPERS" type="fix">48718 - Make the creation of multiple, un-modified fonts in a row in XSSF match the old HSSF behaviour</action>
|
||||||
|
@ -77,6 +77,16 @@ public class DataFormatter {
|
|||||||
/** A regex to find patterns like [$$-1009] and [$?-452]. */
|
/** A regex to find patterns like [$$-1009] and [$?-452]. */
|
||||||
private static final Pattern specialPatternGroup = Pattern.compile("(\\[\\$[^-\\]]*-[0-9A-Z]+\\])");
|
private static final Pattern specialPatternGroup = Pattern.compile("(\\[\\$[^-\\]]*-[0-9A-Z]+\\])");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A regex to match the colour formattings rules.
|
||||||
|
* Allowed colours are: Black, Blue, Cyan, Green,
|
||||||
|
* Magenta, Red, White, Yellow, "Color n" (1<=n<=56)
|
||||||
|
*/
|
||||||
|
private static final Pattern colorPattern =
|
||||||
|
Pattern.compile("(\\[BLACK\\])|(\\[BLUE\\])|(\\[CYAN\\])|(\\[GREEN\\])|" +
|
||||||
|
"(\\[MAGENTA\\])|(\\[RED\\])|(\\[WHITE\\])|(\\[YELLOW\\])|" +
|
||||||
|
"(\\[COLOR\\s*\\d\\])|(\\[COLOR\\s*[0-5]\\d\\])", Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The decimal symbols of the locale used for formatting values.
|
* The decimal symbols of the locale used for formatting values.
|
||||||
*/
|
*/
|
||||||
@ -165,6 +175,20 @@ public class DataFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Format getFormat(double cellValue, int formatIndex, String formatStr) {
|
private Format getFormat(double cellValue, int formatIndex, String formatStr) {
|
||||||
|
// Excel supports positive/negative/zero, but java
|
||||||
|
// doesn't, so we need to do it specially
|
||||||
|
if(formatStr.indexOf(';') != formatStr.lastIndexOf(';')) {
|
||||||
|
int lastAt = formatStr.lastIndexOf(';');
|
||||||
|
String zeroFormat = formatStr.substring(lastAt+1);
|
||||||
|
String normalFormat = formatStr.substring(0,lastAt);
|
||||||
|
if(cellValue == 0.0) {
|
||||||
|
formatStr = zeroFormat;
|
||||||
|
} else {
|
||||||
|
formatStr = normalFormat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if we already have it cached
|
||||||
Format format = formats.get(formatStr);
|
Format format = formats.get(formatStr);
|
||||||
if (format != null) {
|
if (format != null) {
|
||||||
return format;
|
return format;
|
||||||
@ -195,8 +219,24 @@ public class DataFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Format createFormat(double cellValue, int formatIndex, String sFormat) {
|
private Format createFormat(double cellValue, int formatIndex, String sFormat) {
|
||||||
// remove color formatting if present
|
String formatStr = sFormat;
|
||||||
String formatStr = sFormat.replaceAll("\\[[a-zA-Z]*\\]", "");
|
|
||||||
|
// Remove colour formatting if present
|
||||||
|
Matcher colourM = colorPattern.matcher(formatStr);
|
||||||
|
while(colourM.find()) {
|
||||||
|
String colour = colourM.group();
|
||||||
|
|
||||||
|
// Paranoid replacement...
|
||||||
|
int at = formatStr.indexOf(colour);
|
||||||
|
if(at == -1) break;
|
||||||
|
String nFormatStr = formatStr.substring(0,at) +
|
||||||
|
formatStr.substring(at+colour.length()+1);
|
||||||
|
if(nFormatStr.equals(formatStr)) break;
|
||||||
|
|
||||||
|
// Try again in case there's multiple
|
||||||
|
formatStr = nFormatStr;
|
||||||
|
colourM = colorPattern.matcher(formatStr);
|
||||||
|
}
|
||||||
|
|
||||||
// try to extract special characters like currency
|
// try to extract special characters like currency
|
||||||
Matcher m = specialPatternGroup.matcher(formatStr);
|
Matcher m = specialPatternGroup.matcher(formatStr);
|
||||||
@ -329,23 +369,33 @@ public class DataFormatter {
|
|||||||
|
|
||||||
private Format createNumberFormat(String formatStr, double cellValue) {
|
private Format createNumberFormat(String formatStr, double cellValue) {
|
||||||
StringBuffer sb = new StringBuffer(formatStr);
|
StringBuffer sb = new StringBuffer(formatStr);
|
||||||
for (int i = 0; i < sb.length(); i++) {
|
|
||||||
|
// If they requested spacers, with "_",
|
||||||
|
// remove those as we don't do spacing
|
||||||
|
for(int i = 0; i < sb.length(); i++) {
|
||||||
char c = sb.charAt(i);
|
char c = sb.charAt(i);
|
||||||
//handle (#,##0_);
|
if(c == '_') {
|
||||||
if (c == '(') {
|
if(i > 0 && sb.charAt((i-1)) == '\\') {
|
||||||
int idx = sb.indexOf(")", i);
|
// It's escaped, don't worry
|
||||||
if (idx > -1 && sb.charAt(idx -1) == '_') {
|
continue;
|
||||||
sb.deleteCharAt(idx);
|
} else {
|
||||||
sb.deleteCharAt(idx - 1);
|
if(i < sb.length()-1) {
|
||||||
sb.deleteCharAt(i);
|
// Remove the character we're supposed
|
||||||
i--;
|
// to match the space of
|
||||||
}
|
sb.deleteCharAt(i+1);
|
||||||
} else if (c == ')' && i > 0 && sb.charAt(i - 1) == '_') {
|
}
|
||||||
sb.deleteCharAt(i);
|
// Remove the _ too
|
||||||
sb.deleteCharAt(i - 1);
|
sb.deleteCharAt(i);
|
||||||
i--;
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, handle the other aspects like
|
||||||
|
// quoting and scientific notation
|
||||||
|
for(int i = 0; i < sb.length(); i++) {
|
||||||
|
char c = sb.charAt(i);
|
||||||
// remove quotes and back slashes
|
// remove quotes and back slashes
|
||||||
} else if (c == '\\' || c == '"') {
|
if (c == '\\' || c == '"') {
|
||||||
sb.deleteCharAt(i);
|
sb.deleteCharAt(i);
|
||||||
i--;
|
i--;
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@ public final class TestHSSFDataFormatter extends TestCase {
|
|||||||
"0000.00000%",
|
"0000.00000%",
|
||||||
"0.000E+00",
|
"0.000E+00",
|
||||||
"0.00E+00",
|
"0.00E+00",
|
||||||
|
"[BLACK]0.00;[COLOR 5]##.##",
|
||||||
};
|
};
|
||||||
|
|
||||||
// invalid date formats -- will throw exception in DecimalFormat ctor
|
// invalid date formats -- will throw exception in DecimalFormat ctor
|
||||||
|
@ -19,11 +19,15 @@ package org.apache.poi.ss.usermodel;
|
|||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.usermodel.TestHSSFDataFormatter;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests of {@link DataFormatter}
|
* Tests of {@link DataFormatter}
|
||||||
*
|
*
|
||||||
|
* See {@link TestHSSFDataFormatter} too for
|
||||||
|
* more tests.
|
||||||
*/
|
*/
|
||||||
public class TestDataFormatter extends TestCase {
|
public class TestDataFormatter extends TestCase {
|
||||||
/**
|
/**
|
||||||
@ -40,4 +44,81 @@ public class TestDataFormatter extends TestCase {
|
|||||||
assertEquals("12.34", dfUS.formatRawCellContents(12.34, -1, "@"));
|
assertEquals("12.34", dfUS.formatRawCellContents(12.34, -1, "@"));
|
||||||
assertEquals("12,34", dfFR.formatRawCellContents(12.34, -1, "@"));
|
assertEquals("12,34", dfFR.formatRawCellContents(12.34, -1, "@"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure that colours get correctly
|
||||||
|
* zapped from within the format strings
|
||||||
|
*/
|
||||||
|
public void testColours() {
|
||||||
|
DataFormatter dfUS = new DataFormatter(Locale.US);
|
||||||
|
|
||||||
|
String[] formats = new String[] {
|
||||||
|
"##.##",
|
||||||
|
"[WHITE]##.##",
|
||||||
|
"[BLACK]##.##;[RED]-##.##",
|
||||||
|
"[COLOR11]##.##;[COLOR 43]-##.00",
|
||||||
|
};
|
||||||
|
for(String format : formats) {
|
||||||
|
assertEquals(
|
||||||
|
"Wrong format for: " + format,
|
||||||
|
"12.34",
|
||||||
|
dfUS.formatRawCellContents(12.343, -1, format)
|
||||||
|
);
|
||||||
|
assertEquals(
|
||||||
|
"Wrong format for: " + format,
|
||||||
|
"-12.34",
|
||||||
|
dfUS.formatRawCellContents(-12.343, -1, format)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that random square brackets remain
|
||||||
|
assertEquals("12.34[a]", dfUS.formatRawCellContents(12.343, -1, "##.##[a]"));
|
||||||
|
assertEquals("[ab]12.34[x]", dfUS.formatRawCellContents(12.343, -1, "[ab]##.##[x]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test how we handle negative and zeros.
|
||||||
|
* Note - some tests are disabled as DecimalFormat
|
||||||
|
* and Excel differ, and workarounds are not
|
||||||
|
* yet in place for all of these
|
||||||
|
*/
|
||||||
|
public void testNegativeZero() {
|
||||||
|
DataFormatter dfUS = new DataFormatter(Locale.US);
|
||||||
|
|
||||||
|
String all2dp = "00.00";
|
||||||
|
String alln1dp = "(00.0)";
|
||||||
|
String p1dp_n1dp = "00.0;(00.0)";
|
||||||
|
String p2dp_n1dp = "00.00;(00.0)";
|
||||||
|
String p2dp_n1dp_z0 = "00.00;(00.0);0";
|
||||||
|
String all2dpTSP = "00.00_x";
|
||||||
|
String p2dp_n2dpTSP = "00.00_x;(00.00)_x";
|
||||||
|
String p2dp_n1dpTSP = "00.00_x;(00.0)_x";
|
||||||
|
|
||||||
|
assertEquals("12.34", dfUS.formatRawCellContents(12.343, -1, all2dp));
|
||||||
|
assertEquals("12.34", dfUS.formatRawCellContents(12.343, -1, p2dp_n1dp));
|
||||||
|
assertEquals("12.34", dfUS.formatRawCellContents(12.343, -1, p2dp_n1dp_z0));
|
||||||
|
|
||||||
|
assertEquals("(12.3)", dfUS.formatRawCellContents(12.343, -1, alln1dp));
|
||||||
|
assertEquals("-(12.3)", dfUS.formatRawCellContents(-12.343, -1, alln1dp));
|
||||||
|
assertEquals("12.3", dfUS.formatRawCellContents(12.343, -1, p1dp_n1dp));
|
||||||
|
assertEquals("(12.3)", dfUS.formatRawCellContents(-12.343, -1, p1dp_n1dp));
|
||||||
|
|
||||||
|
assertEquals("-12.34", dfUS.formatRawCellContents(-12.343, -1, all2dp));
|
||||||
|
// TODO - fix case of negative subpattern differing from the
|
||||||
|
// positive one by more than just the prefix+suffix, which
|
||||||
|
// is all DecimalFormat supports...
|
||||||
|
// assertEquals("(12.3)", dfUS.formatRawCellContents(-12.343, -1, p2dp_n1dp));
|
||||||
|
// assertEquals("(12.3)", dfUS.formatRawCellContents(-12.343, -1, p2dp_n1dp_z0));
|
||||||
|
|
||||||
|
assertEquals("00.00", dfUS.formatRawCellContents(0, -1, all2dp));
|
||||||
|
assertEquals("00.00", dfUS.formatRawCellContents(0, -1, p2dp_n1dp));
|
||||||
|
assertEquals("0", dfUS.formatRawCellContents(0, -1, p2dp_n1dp_z0));
|
||||||
|
|
||||||
|
// Spaces are skipped
|
||||||
|
assertEquals("12.34", dfUS.formatRawCellContents(12.343, -1, all2dpTSP));
|
||||||
|
assertEquals("12.34", dfUS.formatRawCellContents(12.343, -1, p2dp_n2dpTSP));
|
||||||
|
assertEquals("(12.34)", dfUS.formatRawCellContents(-12.343, -1, p2dp_n2dpTSP));
|
||||||
|
// assertEquals("12.34", dfUS.formatRawCellContents(12.343, -1, p2dp_n1dpTSP));
|
||||||
|
// assertEquals("(12.3)", dfUS.formatRawCellContents(-12.343, -1, p2dp_n1dpTSP));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user